Showing posts with label Spring MVC. Show all posts
Showing posts with label Spring MVC. Show all posts

Tuesday, 2 April 2013

Creating A Customized Spring User & Persistence

This post explains how to create a customized Spring user and persistence mechanism for authentication. The code is available at GitHub in the Spring-MVC-Customized-User directory.

Things To Take Into Consideration

Before creating a customized user, we need to remind what a user is in Spring. We know from here that a user is an implementation of the UserDetails interface. Spring security also requires a loading mechanism, as an implementation of the UserDetailsService interface. To keep this example simple, we are not going to implement login/logout or other security features.

The UserDetails interface is a bit incomplete in order to define a user in a real application. It defines getters and no setters. It is not a big deal, but the real pain is that the username (a string) is considered as 'the' key. Most software developers will prefer a long id.

To solve these issues, we define a PracticalUser interface:
public interface PracticalUserDetails
        extends UserDetails, CredentialsContainer {

    long getId();

    void setPassword(String password);

    void setAccountExpired(boolean b);

    void setAccountLocked(boolean b);

    void setCredentialsExpired(boolean b);

    void setEnabled(boolean b);

    void setAuthorities(
        Collection<? extends GrantedAuthority> authorities);

}
Typically, one would use JPA annotations on the implementation bean and save it in a database in a real application. However, for this example, the DAO will register users in an in-memory map as described further.

The UserDetailsService interface does not provide a get user per name or id, which is necessary for an administrator (for example). More, it does not allow to retrieve all existing users' id and name, or to update or insert users, or even to delete them.

Therefore, we create a PracticalUserDetailsService interface to solve these issues:
public interface PracticalUserDetailsService
        extends UserDetailsService {

    Set<PracticalUserDetailsDAO.UserIdentifiers> getUsers();

    void deleteUser(long id);

    void upsertUser(PracticalUserDetails user);

    PracticalUserDetails getUser(long id);

    PracticalUserDetails getUser(String username);

}
The corresponding implementation is called PracticalUserDetailsServiceInMemory for this example.

In-Memory DAO

To keep this example simple, we define a simple PracticalUserDetailsDAO:
public interface PracticalUserDetailsDAO<U extends PracticalUserDetails> {

    void create(U user);

    boolean contains(U user);

    U read(String username);

    U read(long id);

    void update(U user);

    void delete(String username);

    void delete(long id);

    interface UserIdentifiers {
        long getId();
        String getUsername();
    }

    Set<UserIdentifiers> getUsers();

}
We also define a special user id and name identifier interface to retrieve the set of existing user data, without returning all users. Our implementation of PracticalUserDetailsDAO is PracticalUserDetailsDAOInMemory.

In a real implementation, using a JPA Repository is more appropriate.

Configuration

In the security.xml file, we define our practical user detail service (it will be registered in the authentication manager) and the in-memory DAO bean:
<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <http auto-config="true">
    </http>

    <authentication-manager alias="authenticationManager">
        <authentication-provider user-service-ref='practicalUserDetailsServiceInMemory' />
    </authentication-manager>

    <beans:bean id="pud"
        class="com.jverstry.DAO.PracticalUserDetailsDAOInMemory">
    </beans:bean>

</beans:beans>

The JSP Pages

We use two pages. The main page displays registered users (together with a delete link) and registration form:


The second page is displayed when the Create User button is clicked to check the name and the password:


The Controller

The controller is used to check the username and password:
@Controller
public class MyController {

    @Autowired
    private PracticalUserDetailsServiceInMemory pudm;

    @RequestMapping(value = "/")
    public ModelAndView index() {

        ModelAndView result = new ModelAndView("index");

        result.addObject("users", this.pudm.getUsers());

        return result;

    }

    @RequestMapping(value = "/delete/{id}")
    public String delete(@PathVariable(value="id") String id) {

        this.pudm.deleteUser(Long.parseLong(id));

        return "redirect:/";

    }

    @RequestMapping(value = "/create")
    @SuppressWarnings("AssignmentToMethodParameter")
    public ModelAndView add(
            @RequestParam(value="name")
            String name,
            @RequestParam(value="password")
            String password) {

        name = StringUtils.replace(name, " ", "");
        password = StringUtils.replace(password, " ", "");

        String errorMsg = "";

        if ( name.length() == 0 ) {
            errorMsg += "Name is empty ";
        }

        if ( password.length() == 0 ) {
            errorMsg += "Password is empty ";
        }

        if ( errorMsg.isEmpty() ) {
            this.pudm.upsertUser(new PracticalUserDetailsImpl(name, password));
        }

        ModelAndView result = new ModelAndView("create");

        result.addObject("errorMsg", errorMsg);
        result.addObject("username", name);

        return result;

    }

}

Running The Example

One can run it using the maven tomcat:run goal. Then, browse:

  http://localhost:9191/spring-mvc-customized-user/

More Spring related posts here.

Execute Spring ACL SQL Script In Memory

This post describes how to execute the Spring ACL script to create ACL tables in an in-memory HSQL database instance. The code is available at GitHub in the Execute-ACL-SQL-Scripts-In-Memory directory.

In-Memory DataSource

We are using a configuration classe implementing the DisposableBean interface to shut down the created HSQL embedded database nicely.
@Configuration
public class InMemoryDataSource implements DisposableBean {

    private EmbeddedDatabase ed;

    @Bean(name="hsqlInMemory")
    public EmbeddedDatabase hsqlInMemory() {

        if ( this.ed == null ) {

            EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();

            this.ed = builder.setType(EmbeddedDatabaseType.HSQL)
                .addScript("aclSchema.sql").build();

        }

        return this.ed;

    }

    @Override
    public void destroy() {

        if ( this.ed != null ) {
            this.ed.shutdown();
        }

    }

}
When creating the database, we also have the aclSchema.sql script executed. It must be located at the root of the resource directory:


The content of the script is taken from the Spring documentation appendix.

Checking Table Creation

We extract the list table of tables in the controller. Technically speaking, we should do this at the service/DAO level, but for the sake of this example, we'll keep it simple:
@Controller
public class MyController {

    @Autowired
    EmbeddedDatabase hsqlInMemory;

    @RequestMapping(value = "/")
    public ModelAndView home() {

        ModelAndView result = new ModelAndView("index");

        ArrayList<String> tables = new ArrayList<String>();

        JdbcTemplate tplate = new JdbcTemplate(hsqlInMemory);

        SqlRowSet retr = tplate.queryForRowSet(
            "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES");

        while (retr.next()) {
            tables.add(retr.getString(1));
        }

        result.addObject("tables", tables);

        return result;

    }

}

Running The Example

One can run it using the maven tomcat:run goal. Then, browse:

  http://localhost:8585/execute-acl-sql-scripts-in-memory/

We find the tables we have created:


More Spring related posts here.

Friday, 8 March 2013

Exiting From Google's Sandbox In A Week

Sharing the experience acquired while trying to get a keyword-stuffed site out of Google's sandbox. I explain how I succeeded faster than methods described on the net so far. Not a silver bullet, but surely a boost. In less than a week, I got my site at search result position number 3 for its title keywords:

Out Of Google Sandbox - Your World Clocks

As a reminder, the Google Sandbox effect is observed when a site is indexed by Google, but it does not rank well or at all for keywords it should rank for. The site: command returns pages of your website, proving it is indexed and not banned, but its pages do not appear in search results.

Google denies there is a sandbox where it would park some sites, but it acknowledges there is something in its algorithms which produces a sandbox effect for sites considered as spam. My site would qualify as spam since it was keyword stuffed.

I had registered my site URL in Google Webmaster Tools (GWT) and noticed little to no activity. No indexing of pages and keywords. Fetch as Google would not help. I saw a spike in Crawl Stats for a couple of days, then it fell flat. The site would get no queries, yet the site: command returned its main page.

So, I cleared my site from everything considered spam. I used to following online tools to find my mistakes:

I used Fetch as Google in GWT again, but it did not help get it out of the Sandbox effect. I read all the posts I could find on the net about this topic. Basically, everyone recommends using white hat SEO techniques (more quality content, quality backlinks, etc...) in order to increase the likelihood Google bots will crawl your site again: "It could take months before you get out of the sandbox...!!!"

Not true. I have found a way which showed some results in less than a week. My site is now ranked at the 3rd search result position for its niche keyword. I can see my 'carefully selected' keywords in GWT's Content Keywords page.

So, here is the procedure:
  1. The first step is indeed to clear any spam and bad SEO practices from your site. It is a prerequisite. The following does not work if you don't perform this step with integrity.
  2. Next, make sure your site has a sitemap.xml and a robots.txt file. Make sure the sitemap is complete enough (i.e., it lists all your site's pages or at least the most important ones).
  3. Then, register your sitemap.xml in your robots.txt. You can submit your sitemap.xml to GWT, but it is not mandatory.
  4. Use Fetch as Google to pull your robots.txt in GWT and submit the URL. This makes sure your robots.txt is reachable by Google. It avoids loosing time.
  5. Make sure there is a <lastmod> tag for each page in your sitemap, and make sure you update it to a recent date when you have updated a page. This is especially important if your page contained spam! Keep updating this tag each time you modify a page.
  6. If you don't cheat with the <lastmod> tag, I have noticed Google responds well to it.
  7. Wait for about a week to see unfolding results.
  8. It is as simple as that. No need for expensive SEO consulting!
My site was new and did not have quality/high PR backlinks. So the probability it would be revisited after clearing the spam was low. It is a chicken and egg problem. Nothing happened for two weeks after I had removed the spam. It is only after I applied the above technique that I obtained tangible results!

I suspect this method works better than everything suggested so far, because Google bots crawl robots.txt frequently. The sitemap is revisited more often and therefore, Google knows faster that pages have been updated. Hence, it re-crawls them faster, which increase the likelihood of proper re-indexing. No need to wait months for bots to come back. It eliminates the chicken and egg issue.

I don't think this method would work with sites which got penalized because of one bought fake backlinks or traffic. I think shaking those bad links and traffic away would be a prerequisite too. If this can't be achieved, some have suggested using a new URL. I have never tried this, because I never bought links and traffics, but I am reckon this would be part of the solution.

Why did I keyword-stuffed my site in the first place? Because, I was frustrated by GWT which would not show relevant indexing data fast enough for new sites, even when clean SEO was applied. Moreover, GWT does not tell when a site falls into the sandbox effect. Google gives you the silent treatment. This is a recipe for disaster when it comes to creating a trusting and educated relationship with publishers.

Not everyone is a evil hacker!

Thursday, 7 March 2013

Spring JpaRepository Example (In-Memory)

This post describes a simple Spring JpaRepository example using an in memory HSQL database. The code example is available from GitHub in the Spring-JpaRepository directory. It is based on the Spring-MVC-With-Annotations example and information available here.

JPA Repository

We implement a dummy bean for this example:
@Entity
@AutoProperty
public class SomeItem {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long Id;

    private String someText;

    /* ...Setters & Getters */

}
and the corresponding JpaRepository:
@Transactional
public interface SomeItemRepository
        extends JpaRepository<SomeItem, Long> {

}

Service & Controller

Next, we implement a service where our repository will be injected. We also populate the repository with dummy data:
@Service
@Repository
public class SomeItemService {

    @Autowired
    private SomeItemRepository someItemRepository;

    @PostConstruct
    @Transactional
    public void populate() {

        SomeItem si = new SomeItem();
        si.setSomeText("aaa");
        someItemRepository.saveAndFlush(si);

        si = new SomeItem();
        si.setSomeText("bbb");
        someItemRepository.saveAndFlush(si);

        si = new SomeItem();
        si.setSomeText("ccc");
        someItemRepository.saveAndFlush(si);

    }

    @Transactional(readOnly=true)
    public List<SomeItem> getAll() {

        return someItemRepository.findAll();

    }

    @SuppressWarnings("AssignmentToMethodParameter")
    @Transactional
    public SomeItem saveAndFlush(SomeItem si) {

        if ( si != null ) {
            si = someItemRepository.saveAndFlush(si);
        }

        return si;

    }

    @Transactional
    public void delete(long id) {

        someItemRepository.delete(id);

    }

}
and a controller:
@Controller
public class MyController {

    @Autowired
    private SomeItemService someItemService;

    @RequestMapping(value = "/")
    public ModelAndView index() {

        ModelAndView result = new ModelAndView("index");
        result.addObject("items", this.someItemService.getAll());

        return result;

    }

    @RequestMapping(value = "/delete/{id}")
    public String delete(
        @PathVariable(value="id") String id) {

        this.someItemService.delete(Long.parseLong(id));

        return "redirect:/";

    }

    @RequestMapping(value = "/create")
    @SuppressWarnings("AssignmentToMethodParameter")
    public String add() {

        SomeItem si = new SomeItem();
        si.setSomeText("Time is: " + System.currentTimeMillis());

        this.someItemService.saveAndFlush(si);

        return "redirect:/";

    }

}

JPA Configuration

On top of creating an entity manager based on an in-memeory instance of HSQL database, we enable JPA repositories with the @EnableJpaRepositories annotation:
@Configuration
@EnableJpaRepositories(basePackages={"com.jverstry"})
@EnableTransactionManagement
public class JpaConfig implements DisposableBean {

    private EmbeddedDatabase ed;

    @Bean(name="hsqlInMemory")
    public EmbeddedDatabase hsqlInMemory() {

        if ( this.ed == null ) {
            EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
            this.ed = builder.setType(EmbeddedDatabaseType.HSQL).build();
        }

        return this.ed;

    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(){

        LocalContainerEntityManagerFactoryBean lcemfb
            = new LocalContainerEntityManagerFactoryBean();

        lcemfb.setDataSource(this.hsqlInMemory());
        lcemfb.setPackagesToScan(new String[] {"com.jverstry"});

        lcemfb.setPersistenceUnitName("MyPU");

        HibernateJpaVendorAdapter va = new HibernateJpaVendorAdapter();
        lcemfb.setJpaVendorAdapter(va);

        Properties ps = new Properties();
        ps.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
        ps.put("hibernate.hbm2ddl.auto", "create");
        lcemfb.setJpaProperties(ps);

        lcemfb.afterPropertiesSet();

        return lcemfb;

    }

    @Bean
    public PlatformTransactionManager transactionManager(){

        JpaTransactionManager tm = new JpaTransactionManager();

        tm.setEntityManagerFactory(
            this.entityManagerFactory().getObject() );

        return tm;

    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
        return new PersistenceExceptionTranslationPostProcessor();
    }

    @Override
    public void destroy() {

        if ( this.ed != null ) {
            this.ed.shutdown();
        }

    }

}

The JSP Page

We create a simple page to list existing items with a delete link, and the possibility to create new items:

 Running The Example

One can run it using the maven tomcat:run goal. Then, browse:

  http://localhost:9191/spring-jparepository/

More Spring related posts here.

Thursday, 14 February 2013

Dealing With Google Webmaster Tools Frustrations

If you don't understand the mechanics behind Google Webmaster Tool (GWT, not to be confused with Google's Web-Toolkit framework) and of page indexing, trying to obtain valid information about your website can be a very frustrating experience, especially if it is a new website. This has even led me to take counter-productive actions in order to solve some of GWT flaws. This post is about sharing some experience and tips.

First, you need to know that GWT is a very slow tool. It will take days, if not weeks to produce correct results and information, unless your website is very popular and already well indexed. Secondly, GWT is obviously aggregating information from multiple Google systems. Each system is producing its own information and if you compare all this information, it is not always coherent. Some of it is outdated or plain out-of-sync.

Understanding The Indexing Process

  1. Crawling - The first step is having Google's bots crawl your page. It is a required step before indexation. Once a page is crawled, the snapshot is stored in Google's cache. It is analyzed later for indexing by another process.
  2. Indexing - Once a page has been crawled, Google may decide to index it or not. You have no direct influence on this process. The delay can vary according to websites. Once indexed, a page is automatically available in search results (says w3d).
  3. Ranking - An indexed page always has a ranking, unless the corresponding website is penalized. In this case, it can be removed from the index.
  4. Caching - It is a service where Google stores copies of your pages. Google confirms it is the cached version of your page which is used for indexing.
There are several reasons why a page may not be indexed, or will have a very low ranking:
  • The page falls under bad SEO practices, which includes keyword stuffing, keyword dilution, duplicate content, or low quality content.
  • The page is made unreachable in your robots.txt.
  • There is no URL link to your page and it does not appear in any sitemap known to Google.
For the sake of simplicity, let's call a clean page "a page which does not fall under bad SEO practices, which is not blocked by your robots.txt and whose URL is known to Google bots via a internal or external links or a sitemap (i.e., it is reachable)".

Is My Page Indexed?

Here is a little procedure to follow:
  • The site: command 
    1. Start by running the site: command against the URL of your page (with and without the www. prefix). If it returns your page, then it is indexed for sure. If not, it does not mean your page has not been indexed or that it won't be indexed soon. The  site: command provides an estimation of indexed pages.
    2. You can use the  site: command against the URL of your website to have an estimation of the pages Google has indexed for your site.
  • The cached: command
    1. If the site: command has returned your page, then the cached: command will tell you which version (i.e. snapshot) it has used (or will soon use) for indexing (or reindexing). Remember there is a delay between crawling/caching and indexing.
    2. Else, if it returned nothing and the cached: command returned a snapshot of your page, it means Google bots have managed to crawl your page. This means indexing may or may not happen soon, depending on Google's decision.
    3. If the cached: command still does not return your page after a couple of days or weeks, then it may indicate that you don't have a clean page.

What Can I Do About It?

Here is another procedure:
  • No confirmation that your page has been crawled
    1. The first step is to make sure your page's URL is part of a sitemap submitted to Google (eventually using GWT for submission). Don't believe that Google will naturally and quickly find your page for crawling, even if it is backlinked.
    2. Double-check that your page's URL is not blocked by your robots.txt.
    3. Add a link to your sitemap in your robots.txt.
    4. Avoid using the GWT's Fetch As Google feature as Google will penalize excessive use with less frequent visits to your site. It does not accelerate the indexing process. It just notifies Google it should check for new/updated content. Google can be a pacha taking its time.
    5. Always prefer submitting a complete and updated sitemap versus using GWT's Fetch As Google feature. You don't need to resubmit a sitemap if its URL is defined in your robots.txt. Search engines revisit robots.txt from time to time.
    6. Take a look at GWT's crawl stats. It will tell you (with a 2-3 days delay) whether Google bots are processing your site.
    7. Double-check that your page is not suffering from bad SEO practices. Such pages can be excluded from the indexing process.
    8. Be patient, it can take days, and sometimes weeks before Google reacts to your page.
    9. Check GWT's index status page, but never forget it reacts very very slowly to changes. If you are in a hurry, you may obtain faster information by running the site: and cache: commands from time to time.
  • Your page is in the cache, but no confirmation of indexation
    1. Double-check that your page is not suffering from bad SEO practices. Such pages can be excluded from Google's index.
    2. If your site contains thousands of pages, Google will often start by indexing only a subset. Typically, it will be those it thinks have a better chance of matching users' search requests. If your page is not part of them, check whether other pages of your site are indexed using your website URL in the site: command.
    3. If, after being patient, your clean page is still not being indexed, then it probably means Google does not find it interesting enough. You need to improve its content first. Next, try to apply more white hat SEO recommendations. Layout design, readability and navigability are often the culprit when content isn't.
  • Your page is in the index, but does not rank well
    1. Double-check that your page is not suffering from bad SEO practices. Such pages can be included in Google Index with a low ranking.
    2. Make sure you are using proper keywords on your page, title and meta description. Perform the traditional white hat SEO optimization tricks. If you got everything right and still don't get traffic, it means users don't find your content interesting or their is too much competition for what your offer.

About New Websites & Under Construction

Because of the slowness of GWT and a lack of understading of its mechanics, I once tried to accelerate the indexing of new websites by first submitting 'under construction' versions, stuffed with relevant keywords. It did not help at all! Not only Google did not index my sites (or with a very bad ranking), once I uploaded the final version a couple of weeks later, Google took weeks to (re)index them properly. Google's cache was soooo out of sync...

I have noticed that Google gives extra premature exposure to new websites to test their success, before letting them float naturally. It also tries to find out how often your pages are updated. With a new website under construction, not only will you fail the premature exposure because there is no valuable content for users, but if there are weeks before you put the first final version of your site online, Google may decide not to come back to your site for weeks too, even if new content is uploaded in the mean time (pretty frustrating). Of course, you can use GWT's Fetch as Google feature, but there is no guarantee it will accelerate the process (at least this is what I observed).

Nowadays, I don't register my websites in GWT prematurely. I wait until a first final version is available for production. Next, I apply all the relevant white hat SEO tricks. Then, I create a proper sitemap and robots.txt. At least, after having uploaded everything in production, I register and submit everything to GWT and monitor the indexation process with GWT's crawl stats, together with the site: and cache: commands, until GWT starts to display coherent data. It has eliminated a lot of frustration and teeth grinding!

Monday, 11 February 2013

Securing A Service And JSP Pages

Securing A Spring Service

When a service is implemented in Spring, it can be secured with the @Secured annotation. It has a parameter where the list of roles can be defined. In order to enable this annotation, one must add the the following line in the Spring Security configuration XML file:

  <security:global-method-security secured-annotations="enabled"/>

A complete example is available here.

Securing A JSP Page

Spring defines its own set of JSP tags to control what is displayed to users. This is achieved with the Authorization tag. The Authentication tag can be used to retrieve user details data too.

Thursday, 7 February 2013

Online Content: Quality, Ranking And Promotion

This post is a summary of thumb rules collected here and there and personal experience about content posted online. It is a living document that I will update from time to time:
  • Love the content or have a genuine passion for it! - People notice when you are being authentic and passionate, or not.
  • Content is king! - The quality of the delivered content influences your ranking much more than anything else, especially on the long term.
  • Know what the users wants! - Which is different than believing you know what the customer/readers/users want. Is it valuable to them? Can they find same or better quality on other websites?
  • Give them what they want! (*) - No matter how good your content is, if they don't want it, they won't take it!
  • Tell them where it is! (*) - If they have to dig a mine to get the gold, they never start digging the mine in the first place, especially if they don't know where the gold is! The famous Field Of Dreams' quote "If you build it they will come!" very seldom works on the Internet.
  • Keyword selection is more complex than you think! - I have been seriously humbled by a tip given by a friend. He recommended using Market Samourai (I have no affiliation with this company). I got to understand I only had half of the keyword game rules right. I have increased this blog's traffic by 8-9% by ajusting 3 keywords. Amazing! Even if you won't use this product, DO watch the tutorial videos. It is an incredibly valuable and free SEO education!
(*) Advice found on Black Hat World. I don't recommend implementing the dirty SEO tricks available there, since sooner or later, Google and others always implement remedies. Sites using those tricks are penalized and loose a lot of ranking. Lack of integrity never pays on the long run...

Tuesday, 8 January 2013

Spring Selenium Tests With Annotations

This post describes how to implement Selenium tests in Java. It is inspired from the post by Alex Collins, with annotations. The code is available on GitHub in the Spring-Selenium-Test directory. Some alternative and much lighter techniques are available to unit test a Spring MVC application. To unit test services, see here.

Page, Configuration & Controller

We create a simple page with 'Hello World':
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Welcome !!!</title>
</head>
<body>
  <h1>
   Hello World !
  </h1>
</body>
</html>
We keep our controller very simple:
@EnableWebMvc
@Configuration
@ComponentScan(basePackages = "com.jverstry")
public class WebConfig extends WebMvcConfigurerAdapter {

    @Bean
    public ViewResolver getViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("WEB-INF/pages/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

}
and our controller too:
@Controller
public class MyController {

    @RequestMapping(value = "/")
    public String home() {
        return "index";
    }

}

For Selenium Testing

We create a configuration for testing. It provides the URL to open the application locally. The application is opened with Firefox:
@Configuration
public class TestConfig {

    @Bean
    public URI getSiteBase() throws URISyntaxException {
        return new URI("http://localhost:10001/spring-selenium-test-1.0.0");
    }

    @Bean(destroyMethod="quit")
    public FirefoxDriver getDrv() {
        return new FirefoxDriver();
    }

}
We also define an abstract class as a basis for all tests. It automatically closes Firefox after the test:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={ TestConfig.class })
public abstract class AbstractTestIT {

    @Autowired
    protected URI siteBase;

    @Autowired
    protected WebDriver drv;

    {
        Runtime.getRuntime().addShutdownHook(new Thread() {
           @Override
           public void run() {
                drv.close();
           }
        });
    }

}
And we implement a selenium test where we make sure our page contains 'Hello World':
public class SeleniumTestIT extends AbstractTestIT {

    @Test
    public void testWeSeeHelloWorld() {
        drv.get(siteBase.toString());
        assertTrue(drv.getPageSource().contains("Hello World"));
    }

}
The maven dependencies are the same as those described in Alex Collins's post.

Building The Application

If you build the application, it will open and close firefox automatically. The test will be successful.

Sunday, 18 November 2012

Spring Internationalization Example (with Annotations)

Spring InternationalizationThis post describes how to implement message internationalization in Spring. The code example is available from GitHub in the Spring-MVC-Internationalization directory. It is based on the Spring MVC with annotations example.

Internationalization

We define two resource bundles (setA and setB) containing string translations for German, French and English. These are created in the src/main/resources maven directory.

Configuration

We need to create:
  • a ResourceBundleMessageSource bean to load the string translations
  • a LocaleChangeInterceptor bean which will intercept requests and extract a parameter value (if available) to detect language changes
  • a SessionLocaleResolver bean to store the user's locale preference in the session
  • to register the LocaleChangeInterceptor in the interceptor registry
 We extend our web configuration:
@EnableWebMvc
@Configuration
@ComponentScan(basePackages = "com.jverstry")
public class WebConfig extends WebMvcConfigurerAdapter {

    ...

    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource result
            = new ResourceBundleMessageSource();

        String[] basenames = {
            "i18n.setA.setA",
            "i18n.setB.setB"
        };

        result.setBasenames(basenames);

        return result;

    }

    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor() {

        LocaleChangeInterceptor result = new LocaleChangeInterceptor();
        result.setParamName("lang");

        return result;

    }

    @Bean
    public LocaleResolver localeResolver() {

        SessionLocaleResolver result = new SessionLocaleResolver();
        result.setDefaultLocale(Locale.ENGLISH);

        return result;

    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(localeChangeInterceptor());
    }

}

Controller

We simply our controller a lot:
@Controller
public class MyController {

    @RequestMapping(value = "/")
    public String home() {
        return "index";
    }

}

JSP Page

We only keep the index.jsp page, where we add links to change the language of displayed messages:
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<!doctype html>
<html lang="en">
<head>
  <title>Welcome To Spring MVC Internationalization !!!</title>
</head>
<body>
  <h1>Spring MVC Internationalization !!!</h1>
  <p>Choose:
      <a href="<c:url value='?lang=en'/>">English</a>
      | <a href="<c:url value='?lang=fr'/>">French</a>
      | <a href="<c:url value='?lang=de'/>">German</a>
  </p>

  <p>Greetings: <spring:message code="greetings" text="missing" /></p>
  <p>Text 2: <spring:message code="text2" text="missing" /></p>
  <p>Current: <c:out value="${pageContext.response.locale}" /></p>
</body>
</html>

Running The Example

Once compiled, the example can be run with mvn tomcat:run. Then, browse:

  http://localhost:8383/spring-mvc-internationalization/

The main page will be displayed:


If you click on German, the German text is displayed:


More Spring related posts here.

Spring Bean XML To Annotation Configuration

Here is an example of converting an XML based bean configuration to a annotation based configuration.

Assuming an XML files contain the following:
<bean id="localeChangeInterceptor"
    class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
    <property name="paramName" value="lang" />
</bean>
<bean id="handlerMapping"
    class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
   <property name="interceptors">
       <ref bean="localeChangeInterceptor" />
   </property>
</bean>
The second beans refers to the first one for initialization.

The corresponding Java with annotation configuration is:
@Configuration
public class MyConfig {

    // ...

    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor() {

        LocaleChangeInterceptor result
            = new LocaleChangeInterceptor();

        result.setParamName("lang");

        return result;

    }

    @Bean
    public DefaultAnnotationHandlerMapping handlerMapping() {

        DefaultAnnotationHandlerMapping result
            = new DefaultAnnotationHandlerMapping();

        Object[] interceptors = {
            localeChangeInterceptor()
        };

        result.setInterceptors(interceptors);

        return result;

    }

}

More Spring related posts here.

Sunday, 11 November 2012

Introduction To Spring JPA Data Features

This post is a quick introduction to Spring JPA Data's (SJD) features. This Spring module is built on top of the Spring Data Commons module, which is a prerequisite read in order to understand this post.

Features

This module offers several features:
  • JpaRepository<T, ID extends Serializable> - This interface extends the CrudRepository and PageAndSortingRepository interfaces of the Spring Data Commons module. It offers a couple of extra flush, find all and delete operations. See here for an operational example.
  • JPA Query Methods - This is a powerful mechanism allowing Spring to create queries from method names in classes/interfaces implementing Repository. For example: List<Invoice> findByStartDateAfter(Date date); is automatically translated into select i from Invoice i where u.startDate > ?1.
  • @Query - Queries can be associated to methods in Repository classes/interfaces. For example, a method can be annotated with @Query("select i from Invoice i where u.startDate > ?1")
  • @Modifying - This annotation can be used in combination with @Query to indicate that the corresponding query will perform modifications. Hence, any outdated entities are cleared first.
  • @Lock - This annotation is used to set the lock mode type (none, optimistic, pessimistic, etc...) for a given @Query.
  • JpaSpecificationExecutor and Specification - This interface adds a couple find and count of methods to repository classes/interfaces. All, have a Specification  parameter, which add predicates (i.e., where clauses) to corresponding queries.
  • Auditable, AbstractPersistable and AbstractAuaditable - The Auditable interface allows one to track modifications made to an entity (creation, last modification...). The AbstractPersistable and AbstractAuditable are abstract class facilities avoiding the boilerplate code.
  • MergingPersistenceUnitManager - If a developer decides to modularize his/her application, he/she may still want to use a unique persistence unit, even though they are declared in separate XML file. The MergingPersistenceUnitManager solves this issue.
At last, to enable JPA repositories, the:

    @EnableJpaRepositories("com.my.repositories")

should be set on a Java @Configuration class.

More Spring related posts here.

Introduction To Spring Data Commons Features

This post is a quick introduction to Spring Data Common's (SDC) features.

Features

This Spring module provides a set of interfaces to manipulate data in repositories:
  • Repository - This is a marker interface indicating which object are going to access the repository.
  • CrudRepository<T, ID extends Serializable> - This interface extends Repository and provides a set of CRUD (Create, Read, Update, Delete) methods to manipulate T objects having ID as a key.
  • PageAndSortingRepository<T, ID extends Serializable> - This interface extends CrudRepository and provides method to fetch T objects in a sorted way or using pages.
  • Pageable & PageRequest - The Pageable interface is implemented by PageRequest. Page requests are created to indicate which page and page sizes should be used to fetch objects from the PageAndSortingRepository interface.
  • Page<T> - This interface contains the fetched objects returned for a given page request.
The above repository interfaces can expose too many methods for some developers. For example, one may not be comfortable with the idea of exposing write methods. The solution is to create your own customized repository interface and annotate it with:

    @RepositoryDefinition(
        domainClass=MyClass.class,
        idClass=MyClassID.class)

Then, copy the the repository methods you want to expose in this customized interface and Spring will deal with them.

There are situations where developers want to implement their own repository interfaces by extending the repository interfaces available in SDC. However, these interfaces should not be instantiated in their applications. To prevent this, they can use the @NoRepositoryBean on these customized interfaces.

More Spring related posts here.

The Authenticated User Concept In Spring Security

A user, in the Spring Security context, is an instance of a class implementing the UserDetails interface. One can use it to check whether:
  • the user account is expired or locked
  • the user is enabled or not
  • credentials are expired or not
As a reminder, authentication requests are managed by an authentication manager delegating these to authentication providers. The laters can be used to authenticate authentication requests.

By default, Spring configures a DaoAuthenticationProvider instance, and registers it in the default authentication manager. The main purpose of this provider is to let software developers choose the way they want to store UserDetails by setting an object implementing UserDetailsService. Such services have one function: load a user's details from its name. That's it! It can be a database, an in-memory database, etc...

If you want to implement your own UserDetailsService, Marc Serrano has provided a detailed example using a JPA Repository which eliminates a lot of the boiler-plate code. Such repositories are part of the Spring JPA Data features.

To implement a customized user and corresponding persistence, see the example available here.

More Spring related posts here.

Thursday, 8 November 2012

Spring MVC REST Calls With HTTP Only

This post describes how to perform REST calls to a Spring MVC application using HTTP only. This example is a variation of the Spring MVC REST Calls With Ajax example. The code is available on GitHub in the Spring-REST-With-HTML-Only directory.

Web.xml

We need to add the HiddenHttpMethodFilter to our web.xml. It searches HTML form PUTs for a _method parameter. If the corresponding value is GET, PUT, POST or DELETE, the call is transformed into a REST call before it is transmitted to the controllers:
...
<servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<filter>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <servlet-name>MyServlet</servlet-name>
</filter-mapping>
...

Main Page

We replace the buttons by HTML post forms:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!doctype html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html;" charset=UTF-8">
  <title>Welcome To REST With HTML Only !!!</title>
</head>
<body>
    <h1>Welcome To REST With HTML Only !!!</h1>
    <form action="<c:url value='/MyData/123466/'/>"
          method="post" >
        <input type="hidden" name="_method" value="GET">
        <input type="submit" value="GET">
    </form>
    <form action="<c:url value='/MyData'/>"
          method="post" >
        <input type="hidden" name="time" value="555555">
        <input type="hidden" name="message" value="User PUT call !!!">
        <input type="hidden" name="_method" value="PUT">
        <input type="submit" value="PUT">
    </form>
    <form action="<c:url value='/MyData'/>"
          method="post" >
        <input type="submit" value="POST">
    </form>
    <form action="<c:url value='/MyData/654321'/>"
          method="post" >
        <input type="hidden" name="_method" value="DELETE">
        <input type="submit" value="DELETE">
    </form>
</body>
</html>

Controller

We need to modify our controller for PUT calls:
@Controller
@RequestMapping(value = "/MyData")
public class MyRESTController {

    @RequestMapping(value="/{time}", method = RequestMethod.GET)
    public @ResponseBody MyData getMyData(
            @PathVariable long time) {

        return new MyData(time, "REST GET Call !!!");
    }

    @RequestMapping(method = RequestMethod.PUT)
    public @ResponseBody MyData putMyData(
            @RequestParam("time") long time,
            @RequestParam("message") String message) {

        return new MyData(time, message);
    }

    @RequestMapping(method = RequestMethod.POST)
    public @ResponseBody MyData postMyData() {
        return new MyData(
            System.currentTimeMillis(), "REST POST Call !!!");
    }

    @RequestMapping(value="/{time}", method = RequestMethod.DELETE)
    public @ResponseBody MyData deleteMyData(
            @PathVariable long time) {

        return new MyData(time, "REST DELETE Call !!!");
    }

}

Running The Example

Once compiled, the example can be run with mvn tomcat:run. Then, browse:

  http://localhost:8585/spring-rest-with-html-only

The main page will be displayed:

Spring MVC REST Calls With HTML Only


If you click on a button, the corresponding JSON will be displayed:

Spring MVC With HTML Only JSON
More Spring related posts here.

Spring MVC REST Calls From Java

Sometimes, web applications running on servers need to access REST resources located on other servers. From a REST perspective, the physical server act as a logical REST client. This example describes how to proceed. It is based on the Spring MVC REST Calls With Ajax example. The code is available on GitHub in the Spring-Server-Side-REST-Call directory.

Controller

To simulate a remote server, we create a fake remote controller:
@Controller
@RequestMapping(value = "/MyRemoteData")
public class MyRemoteController {

    @RequestMapping(value="/{time}", method = RequestMethod.GET)
    public @ResponseBody MyRemoteData getMyRemoteData(
            @PathVariable long time) {

        return new MyRemoteData(
            "My remote data called at: " + time + " !!!");
    }

}
It return a MyRemoteData object as a JSON:
public class MyRemoteData {

    private String data = "";

    public MyRemoteData() { }

    public MyRemoteData(String message) {
       this.data = message;
    }

    // Setter & Getters

}
We simplify our existing controller to a simple GET. It uses Spring's RestTemplate to make a REST Http GET call to fetch remote data from our 'remote' server:
@Controller
@RequestMapping(value = "/MyData")
public class MyRESTController {

    @RequestMapping(value="/{time}", method = RequestMethod.GET)
    public @ResponseBody MyData getMyData(
            @PathVariable long time) {

        RestTemplate restTemplate = new RestTemplate();

        String remote = "http://localhost:8585/spring-server-side-rest-call/"
            + "MyRemoteData/" + System.currentTimeMillis();

        MyRemoteData mrd = restTemplate.getForObject(
            remote, MyRemoteData.class);

        return new MyData(System.currentTimeMillis(), mrd.getData());

    }

}

Main Page

We simplify our main page and only keep our GET button:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!doctype html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html;" charset=UTF-8">
  <script type="text/javascript"
    src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
  </script>
  <script type="text/javascript"
    src="<c:url value='/resources/js/SpringServerSideRestCall.js'/>">
  </script>
  <title>Welcome To REST With Java !!!</title>
</head>
<body>
  <h1>Welcome To REST With Java !!!</h1>
  <button type="button" onclick="RestGet()">GET</button>
</body>
</html>
Ditto for our javascript:
var prefix = "/spring-server-side-rest-call";

var RestGet = function() {

    $.ajax({
        type: 'GET',
        url:  prefix + "/MyData/" + Date.now(),
        dataType: 'json',
        async: true,
        success: function(result) {
            alert("At " + result.time
                + ": " + result.message);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            alert(jqXHR.status + " " + jqXHR.responseText);
        }
    });

}

Running The Example

Once compiled, the example can be run with mvn tomcat:run. Then, browse:

  http://localhost:8585/spring-server-side-rest-call/

The main page will be displayed:

Spring REST Calls From Java

If you click on get, a pop-up is displayed:


More Spring related posts here.

Wednesday, 7 November 2012

Spring MVC REST Calls With Ajax

This post provides a simple example of REST calls to a Spring MVC web application. It is based on the Serving Static Resources With Spring MVC and Fetching JSON With Ajax In Spring MVC Context example. The code is available on GitHub in the Spring-REST-With-Ajax directory.

Main Page

Our main page contains four buttons linked to Javascript functions performing Ajax calls:
...
<body>
<h1>Welcome To REST With Ajax !!!</h1>
<button type="button" onclick="RestGet()">GET</button>
<button type="button" onclick="RestPut()">PUT</button>
<button type="button" onclick="RestPost()">POST</button>
<button type="button" onclick="RestDelete()">DELETE</button>
</body>
...

Javascript

Our Javascript file contains the four functions:
var prefix = "/spring-rest-with-ajax";

var RestGet = function() {
        $.ajax({
        type: 'GET',
        url:  prefix + "/MyData/" + Date.now(),
        dataType: 'json',
        async: true,
        success: function(result) {
            alert("At " + result.time
                + ": " + result.message);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            alert(jqXHR.status + " " + jqXHR.responseText);
        }
   });
}

var RestPut = function() {

    var JSONObject= {
        "time": Date.now(),
        "message": "User PUT call !!!"
    };
 
    $.ajax({
        type: 'PUT',
        url:  prefix + "/MyData",
        contentType: "application/json; charset=utf-8",
        data: JSON.stringify(JSONObject),
        dataType: 'json',
        async: true,
        success: function(result) {
            alert("At " + result.time
                + ": " + result.message);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            alert(jqXHR.status + " " + jqXHR.responseText);
        }
    });
}

var RestPost = function() {
        $.ajax({
        type: 'POST',
        url:  prefix + "/MyData",
        dataType: 'json',
        async: true,
        success: function(result) {
            alert("At " + result.time
                + ": " + result.message);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            alert(jqXHR.status + " " + jqXHR.responseText);
        }
    });
}

var RestDelete = function() {
        $.ajax({
        type: 'DELETE',
        url:  prefix + "/MyData/" + Date.now(),
        dataType: 'json',
        async: true,
        success: function(result) {
            alert("At " + result.time
                + ": " + result.message);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            alert(jqXHR.status + " " + jqXHR.responseText);
        }
    });
}

Controller

Our controller captures the REST calls and returns a JSON. In a real applications, one would perform CRUD operations rather than returning JSONs:
@Controller
@RequestMapping(value = "/MyData")
public class MyRESTController {

    @RequestMapping(value="/{time}", method = RequestMethod.GET)
    public @ResponseBody MyData getMyData(
            @PathVariable long time) {
  
        return new MyData(time, "REST GET Call !!!");
    }
 
    @RequestMapping(method = RequestMethod.PUT)
    public @ResponseBody MyData putMyData(
            @RequestBody MyData md) {
  
        return md;
    }
 
    @RequestMapping(method = RequestMethod.POST)
    public @ResponseBody MyData postMyData() {
 
        return new MyData(System.currentTimeMillis(),
            "REST POST Call !!!");
    }

    @RequestMapping(value="/{time}", method = RequestMethod.DELETE)
    public @ResponseBody MyData deleteMyData(
            @PathVariable long time) {
  
        return new MyData(time, "REST DELETE Call !!!");
    }
}

Running The Example

Once compiled, the example can be run with mvn tomcat:run. Then, browse:

  http://localhost:8585/spring-rest-with-ajax/

The main page will be displayed:



If you click on any button, a pop-up will be displayed:


See here for more about REST • More Spring related posts here.

Tuesday, 6 November 2012

Spring MVC Error Handling

This post describes the different techniques to perform error handling in Spring MVC 3. The code is available on GitHub in the Spring-MVC-Error-Handling directory. It is based on the Spring MVC With Annotations examples.

Handling Exceptions Before Spring 3

Before Spring 3, exceptions were handled with HandlerExceptionResolvers. This interface defines a single method:
ModelAndView resolveException(
  HttpServletRequest request,
  HttpServletResponse response,
  Object handler,
  Exception ex)
Notice it returns a ModelAndView object. Therefore, encountering an error meant being forwarded to a special page. However, this method is not suited for REST Ajax calls to JSONs (for example). In this case, we do not want to return a page, and we may want to return a specific HTTP status code. A solution, described further, is available.

For the sake of this example, two fake CustomizedException1 and CustomizedException2 exceptions have been created. To map customized exceptions to views, one could (and can still) use a SimpleMappingExceptionResolver:
SimpleMappingExceptionResolver getSimpleMappingExceptionResolver() {

    SimpleMappingExceptionResolver result
        = new SimpleMappingExceptionResolver();

    // Setting customized exception mappings
    Properties p = new Properties();
    p.put(CustomizedException1.class.getName(), "Errors/Exception1");
    result.setExceptionMappings(p);

    // Unmapped exceptions will be directed there
    result.setDefaultErrorView("Errors/Default");

    // Setting a default HTTP status code
    result.setDefaultStatusCode(HttpStatus.BAD_REQUEST.value());

    return result;

}
We map CustomizedException1 to the Errors/Exception1 JSP page (view). We also set a default error view for unmapped exception, namely CustomizedException2 in this example. We also set a default HTTP status code.

Here is the Exception1 JSP page, the default page is similar:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!doctype html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html;" charset=UTF-8">
  <title>Welcome To Exception I !!!</title>
</head>
<body>
    <h1>Welcome To Exception I !!!</h1>
    Exception special message:<
    ${exception.specialMsg}
    <a href="<c:url value='/'/>">Home</a>
</body>
</html>
We also create a dummy error controller to help triggering these exceptions:
@Controller
public class TriggeringErrorsController {

    @RequestMapping(value = "/throwCustomizedException1")
    public ModelAndView throwCustomizedException1(
        HttpServletRequest request,HttpServletResponse response)
            throws CustomizedException1 {

        throw new CustomizedException1(
            "Houston, we have a problem!");
    }

    @RequestMapping(value = "/throwCustomizedException2")
    public ModelAndView throwCustomizedException2(
        HttpServletRequest request,HttpServletResponse response)
            throws CustomizedException2 {

        throw new CustomizedException2(
            "Something happened on the way to heaven!");
    }

    ...

}
Before Spring 3, one would declare a SimpleMappingExceptionResolver as a @Bean in web.xml. However, we will use a HandlerExceptionResolverComposite which we will describe later.

We also configure a target page for HTTP status codes in web.xml, which is an other way to deal with issues:
<error-page>
    <error-code>404</error-code>
    <location>/WEB-INF/pages/Errors/My404.jsp</location>
</error-page>

What Is New Since Spring 3.X?

The @ResponseStatus annotation is a new mean to set a Http status code when a method is invoked. These are handled by the ResponseStatusExceptionResolver. The @ExceptionHandler annotation facilitates the handling of exceptions in Spring. Such annotations are processed by the AnnotationMethodHandlerExceptionResolver.

The following illustrates how these annotations can be used to set an HTTP status code to the response when our customized exception is triggered. The message is returned in the response's body:
@Controller
public class TriggeringErrorsController {

    ...

    @ExceptionHandler(Customized4ExceptionHandler.class)
    @ResponseStatus(value=HttpStatus.BAD_REQUEST)
    @ResponseBody
    public String handleCustomized4Exception(
        Customized4ExceptionHandler ex) {

        return ex.getSpecialMsg();

    }

    @RequestMapping(value = "/throwCustomized4ExceptionHandler")
    public ModelAndView throwCustomized4ExceptionHandler(

        HttpServletRequest request,HttpServletResponse response)
            throws Customized4ExceptionHandler {

        throw new Customized4ExceptionHandler("S.O.S !!!!");

    }

}
On the user side, if one uses an Ajax call, the error can be retrieved with the following (we are using JQuery):
$.ajax({
    type: 'GET',
    url:  prefix + "/throwCustomized4ExceptionHandler",
    async: true,
    success: function(result) {
        alert('Unexpected success !!!');
    },
    error: function(jqXHR, textStatus, errorThrown) {
        alert(jqXHR.status + " " + jqXHR.responseText);
    }
});
Some people using Ajax like to return a JSON with the error code and some message to handle exceptions. I find it overkill. A simple error number with a message keeps it simple.

Since we are using several resolvers, we need a composite resolver (as mentioned earlier):
@Configuration
public class ErrorHandling {

    ...

    @Bean
    HandlerExceptionResolverComposite getHandlerExceptionResolverComposite() {

        HandlerExceptionResolverComposite result
            = new HandlerExceptionResolverComposite();

        List<HandlerExceptionResolver> l
            = new ArrayList<HandlerExceptionResolver>();

        l.add(new AnnotationMethodHandlerExceptionResolver());
        l.add(new ResponseStatusExceptionResolver());
        l.add(getSimpleMappingExceptionResolver());
        l.add(new DefaultHandlerExceptionResolver());

        result.setExceptionResolvers(l);

        return result;

}
The DefaultHandlerExceptionResolver resolves standard Spring exceptions and translates them to corresponding HTTP status codes.

Running The Example

Once compiled, the example can be run with mvn tomcat:run. Then, browse:

  http://localhost:8585/spring-mvc-error-handling/

The main page will look like this:

Spring MVC Error Handling

If you click on the Exception 1 link, the following page will display:

Spring MVC Exception Handling

If you click on the Exception 2 link, the following page will display:


If you click on the Exception Handler button, a pop-up will be displayed:

Spring MVC Exception Handling Pop-Up

These techniques are enough to cover error handling in Spring.

More Spring related posts here.