Spring+SpringMVC+SpringData+JPA(Hibernate实现)无XML配置

JDK版本

JDK版本.jpg


  本文的目标是采用基于Java配置的方式搭建Spring+SpringMVC+SpringData+JPA。本文只是简单的演示一下具体的配置,没有任何繁琐复杂的逻辑业务,目的是体验一下SpringXML该如何配置。最后展示一下SpringData提供的分页封装类Page的效果。


项目依赖
    <properties>
        <argLine>-Dfile.encoding=UTF-8</argLine>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
        <spring.version>4.3.2.RELEASE</spring.version>
        <spring.data.version>1.10.2.RELEASE</spring.data.version>
        <hibernate5.version>5.2.2.Final</hibernate5.version>
        <hibernate5.validation.version>5.2.4.Final</hibernate5.validation.version>
        <hibernate4.version>4.3.11.Final</hibernate4.version>
        <hibernate4.validation.version>4.3.2.Final</hibernate4.validation.version>
        <jackson.version>2.8.1</jackson.version>
        <project.context.path>/</project.context.path>
        <project.port>80</project.port>
    </properties>

<dependencies>

            <!-- web -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>${spring.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>javax.el</groupId>
                        <artifactId>javax.el-api</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>javax.servlet.jsp.jstl</groupId>
                        <artifactId>javax.servlet.jsp.jstl-api</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>javax.servlet.jsp</groupId>
                        <artifactId>javax.servlet.jsp-api</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
                <version>1.2</version>
            </dependency>
            <dependency>
                <groupId>taglibs</groupId>
                <artifactId>standard</artifactId>
                <version>1.1.2</version>
            </dependency>

            <dependency>
                <groupId>javax</groupId>
                <artifactId>javaee-web-api</artifactId>
                <version>7.0</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.dataformat</groupId>
                <artifactId>jackson-dataformat-xml</artifactId>
                <version>${jackson.version}</version>
            </dependency>
            <!-- web -->

            <!-- service -->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.9</version>
            </dependency>
            <dependency>
                <groupId>aopalliance</groupId>
                <artifactId>aopalliance</artifactId>
                <version>1.0</version>
            </dependency>
            <!-- service -->

            <!-- test -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
            <!-- test -->

            <!-- log -->
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
                <version>1.1.7</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-api</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.logback-extensions</groupId>
                <artifactId>logback-ext-spring</artifactId>
                <version>0.1.4</version>
                <exclusions>
                    <exclusion>
                        <groupId>ch.qos.logback</groupId>
                        <artifactId>logback-classic</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>jcl-over-slf4j</artifactId>
                <version>1.7.21</version>
            </dependency>
            <!-- log -->

            <!-- dao -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-orm</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.0.25</version>
                <exclusions>
                    <exclusion>
                        <groupId>com.alibaba</groupId>
                        <artifactId>jconsole</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>com.alibaba</groupId>
                        <artifactId>tools</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.37</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-jpa</artifactId>
                <version>${spring.data.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.hibernate</groupId>
                        <artifactId>hibernate-entitymanager</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-beans</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-context</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-core</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-tx</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aop</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-ehcache</artifactId>
                <!--<version>${hibernate4.version}</version>-->
                <version>${hibernate5.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-api</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>javax.el</groupId>
                        <artifactId>el-api</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-core</artifactId>
                <!--<version>${hibernate4.version}</version>-->
                <version>${hibernate5.version}</version>
            </dependency>
            <!-- dao -->

            <!-- integration -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <!-- integration -->

            <!-- utility -->
            <dependency>
                <groupId>com.google.code.gson</groupId>
                <artifactId>gson</artifactId>
                <version>2.7</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.16.10</version>
            </dependency>
            <!-- utility -->

        </dependencies>

  说明:本文所使用框架版本大多为作文时的最新版本,其中Spring版本为4.3.2.RELEASEJPA规范版本为2.1,采用Hibernate 5.2.2.Final作为实现,SpringData采用1.10.2.RELEASE版本。要求Serlvet容器必须支持Servlet3.0及以上,即使用tomcat的话必须是7以上,使用jetty的话则必须是8以上。


  首先是Spring的配置,主要配置数据源、entityManagerFactorytransactionManager等。
  需要用到如下两个配置文件:
db.properties

mysql.url = jdbc:mysql:///springmvc
mysql.driverClassName = com.mysql.jdbc.Driver
mysql.username = root
mysql.password =

druid.minIdle = 1
druid.maxActive = 10
druid.testWhileIdle = false

hbm.properties

hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect

hibernate.show_sql = true

hibernate.format_sql = true

hibernate.hbm2ddl.auto = update

## 二级缓存
hibernate.cache.use_second_level_cache = true

hibernate.cache.region.factory_class = org.hibernate.cache.ehcache.EhCacheRegionFactory

hibernate.cache.provider_configuration_file_resource_path = classpath:cache/ehcache.xml

hibernate.cache.use_query_cache = true

# 只有使用 @javax.persistence.Cacheable 注解标注的实体能够被缓存
jpa.shared-cache-mode = ENABLE_SELECTIVE

  SpringConfig应用上下文配置类,该类通常对应着applicationContext.xml文件

package org.junbin.spring.javaconfig.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.hibernate.cfg.Environment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.bind.annotation.ControllerAdvice;

import javax.persistence.SharedCacheMode;
import java.util.HashMap;
import java.util.Map;

/**
 * @author : Chung Junbin
 * @email : <a href="mailto:rekadowney@163.com">发送邮件</a>
 * @createDate : 2016-09-01 10:08
 * @description :
 * <pre>
 *   特别注意:在 Spring 主配置(称为应用上下文配置)类,千万不要基于根目录扫描整个目录,否则它会将 config 目录中的
 * 其他配置类也扫描并实例化,此时使用 JUnit 测试非 Web 环境下时提示没有找到 Web 上下文,导致单元测试失败。
 *   即建议/要求 {@link ComponentScan#basePackages()} 应该具体到 repository 和 service 等 Component 组件的
 * 包路径,而不是包含两者的上级目录
 * </pre>
 */
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false, exposeProxy = true)
@EnableTransactionManagement(proxyTargetClass = false)
@EnableJpaRepositories(basePackages = {"org.junbin.spring.javaconfig.repository"},
        entityManagerFactoryRef = "entityManagerFactory",
        transactionManagerRef = "transactionManager")
@PropertySource(encoding = "UTF-8", value = {"classpath:bundle/db.properties", "classpath:bundle/hbm.properties"})
@ComponentScan(basePackages = {"org.junbin.spring.javaconfig.repository", "org.junbin.spring.javaconfig.service"}, excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, ControllerAdvice.class})
})
public class SpringConfig {

    /**
     * 数据源配置
     */
    @Value(value = "${mysql.url}")
    private String url;
    @Value(value = "${mysql.driverClassName}")
    private String driverClassName;
    @Value(value = "${mysql.username}")
    private String username;
    @Value(value = "${mysql.password}")
    private String password;
    @Value(value = "${druid.minIdle}")
    private int minIdle;
    @Value(value = "${druid.maxActive}")
    private int maxActive;
    @Value(value = "${druid.testWhileIdle}")
    private boolean testWhileIdle;

    /**
     * JPA 规范的 Hibernate 实现
     */
    @Value(value = "${hibernate.show_sql}")
    private boolean showSql;
    @Value(value = "${hibernate.format_sql}")
    private boolean formatSql;
    @Value(value = "${hibernate.hbm2ddl.auto}")
    private String hbm2ddl;
    @Value(value = "${hibernate.dialect}")
    private String dialect;
    /**
     * 二级缓存
     */
    @Value(value = "${hibernate.cache.use_second_level_cache}")
    private boolean useSecondLevelCache;
    @Value(value = "${hibernate.cache.region.factory_class}")
    private String cacheRegionFactory;
    @Value(value = "${hibernate.cache.provider_configuration_file_resource_path}")
    private String cacheProviderConfigLocation;
    @Value(value = "${hibernate.cache.use_query_cache}")
    private boolean useQueryCache;
    @Value(value = "${jpa.shared-cache-mode}")
    private String sharedCacheMode;


    // 必须指定返回类型为 DruidDataSource 才能够执行其中的方法;如果返回 DataSource 类型是没有这两个方法的
    @Bean(name = "dataSource", initMethod = "init", destroyMethod = "close")
    public DruidDataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setMinIdle(minIdle);
        dataSource.setMaxActive(maxActive);
        dataSource.setTestWhileIdle(testWhileIdle);
        return dataSource;
    }

    @Bean(name = "entityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean factoryBean = new
                LocalContainerEntityManagerFactoryBean();
        factoryBean.setDataSource(dataSource());
        factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        factoryBean.setPackagesToScan("org.junbin.spring.javaconfig.domain", "org.junbin.spring.javaconfig.converter.jpa");
        Map<String, Object> jpaPropertyMap = new HashMap<>();
        jpaPropertyMap.put(Environment.DIALECT, dialect);
        jpaPropertyMap.put(Environment.SHOW_SQL, showSql);
        jpaPropertyMap.put(Environment.FORMAT_SQL, formatSql);
        jpaPropertyMap.put(Environment.HBM2DDL_AUTO, hbm2ddl);
        // 二级缓存配置
        jpaPropertyMap.put(Environment.USE_SECOND_LEVEL_CACHE, useSecondLevelCache);
        jpaPropertyMap.put(Environment.CACHE_REGION_FACTORY, cacheRegionFactory);
        jpaPropertyMap.put(Environment.CACHE_PROVIDER_CONFIG, cacheProviderConfigLocation);
        jpaPropertyMap.put(Environment.USE_QUERY_CACHE, useQueryCache);
        factoryBean.setJpaPropertyMap(jpaPropertyMap);
        // 设置只有使用 @javax.persistence.Cacheable 注解标注的实体能够被缓存
        factoryBean.setSharedCacheMode(SharedCacheMode.valueOf(sharedCacheMode));
        return factoryBean;
    }

    @Bean(name = "transactionManager")
    public JpaTransactionManager transactionManager() {
        return new JpaTransactionManager(entityManagerFactory().getObject());
    }

}

  配置SpringMVC,主要配置视图解析器以及配置静态资源映射。
  SpringMVC Web上下文配置类,该类通常对应着serlvet-spring4mvc.xml配置文件

package org.junbin.spring.javaconfig.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

/**
 * @author : Chung Junbin
 * @email : <a href="mailto:rekadowney@163.com">发送邮件</a>
 * @createDate : 2016-09-01 10:09
 * @description :
 * <pre>
 *   不使用 {@link EnableWebMvc} 注解而是直接继承于 {@link WebMvcConfigurationSupport} 或者
 * {@link DelegatingWebMvcConfiguration},之后通过覆盖方法可以实现更多可选功能
 * </pre>
 */
@Configuration
@ComponentScan(basePackages = {"org.junbin.spring.javaconfig.controller"}, useDefaultFilters = false,
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {
                Controller.class, ControllerAdvice.class
        })})
public class SpringMvcConfig extends WebMvcConfigurationSupport {

    private static final String resourceHandler = "/resources/**";
    private static final String resourceLocation = "/resources/";

    @Bean(name = "viewResolver")
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setContentType("text/html; charset=UTF-8");
        return viewResolver;
    }

    // 添加静态资源映射
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler(resourceHandler).addResourceLocations(resourceLocation);
    }

    // 添加 default servlet 支持
    @Override
    protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

}

  接下来针对web.xml的配置类,前面之所以要求使用支持Servlet3.0以上的容器是因为这里我们将不使用web.xml配置文件,全部采用基于Java的方法来配置ServletFilterListener
  这里主要要配置logback的监听器、UTF-8的字符编码过滤器以及OpenEntityManagerInViewFilter
  WebXmlConfig配置类

package org.junbin.spring.javaconfig.config;

import ch.qos.logback.ext.spring.web.LogbackConfigListener;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.filter.CharacterEncodingFilter;

import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.util.EnumSet;

/**
 * @author : Chung Junbin
 * @email : <a href="mailto:rekadowney@163.com">发送邮件</a>
 * @createDate : 2016-09-01 10:20
 * @description :
 */
public class WebXmlConfig implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {

        // logback 监听器
        servletContext.setInitParameter("logbackConfigLocation", "classpath:logback/logback.xml");
        servletContext.addListener(LogbackConfigListener.class);

        // CharacterEncodingFilter 过滤器
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter("UTF-8", true);
        FilterRegistration.Dynamic characterEncodingConfig = servletContext.addFilter(
                "characterEncodingFilter", characterEncodingFilter
        );
        characterEncodingConfig.addMappingForUrlPatterns(
                EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE),// 这里限定所有客户端请求、服务器 forward、服务器 include 的请求全都需要经过 filter 处理
                false, // 在所有当前已经被声明的 Filter 的前面先匹配 URL
                "/*"
        );

        // OpenEntityManagerInViewFilter 过滤器,避免在页面上出现懒加载异常,如果我们全部使用 json 作为传输的话则可以不配置
        OpenEntityManagerInViewFilter openEntityManagerInViewFilter = new OpenEntityManagerInViewFilter();
        FilterRegistration.Dynamic openEntityManagerInViewConfig = servletContext.addFilter(
                "openEntityManagerInViewFilter", openEntityManagerInViewFilter);
        openEntityManagerInViewConfig.addMappingForUrlPatterns(
                EnumSet.of(DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.REQUEST),
                true, // 在所有当前已经被声明的 Filter 的后面匹配 URL
                "/*"
        );

    }

}

  在上面的配置中,我们并没有配置SpringMVCDispatcherServlet,原因是DispatcherServlet比较特殊,我们可以通过继承WebApplicationInitializer的抽象实现类AbstractAnnotationConfigDispatcherServletInitializer来配置它。
  WebInitializer

package org.junbin.spring.javaconfig.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
 * @author : Chung Junbin
 * @email : <a href="mailto:rekadowney@163.com">发送邮件</a>
 * @createDate : 2016-09-01 15:18
 * @description :
 */
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    /**
     * <pre>
     *   配置 Spring 的 {@link org.springframework.web.servlet.DispatcherServlet}
     * 的 {@code url-pattern}
     * </pre>
     */
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    /**
     * <pre>
     *   配置应用上下文,即所有不包括 SpringMVC 等 Web 配置之外的所有配置,
     * 比如:Spring、Hibernate、AOP 等的配置类
     * </pre>
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[]{SpringConfig.class};
    }

    /**
     * <pre>
     *   配置 SpringMVC 等 Web 上下文
     * </pre>
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[]{SpringMvcConfig.class};
    }

}

  接下来演示一下分页功能,首先创建User实体类。

package org.junbin.spring.javaconfig.domain;

import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * @author : Chung Junbin
 * @email : <a href="mailto:rekadowney@163.com">发送邮件</a>
 * @createDate : 2016-09-01 21:35
 * @description :
 */
@Entity
@Table(name = "user")
@Cacheable
public class User implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", nullable = false, updatable = false)
    private int id;

    @Column(name = "username")
    private String username;

    @Column(name = "create_time")
    private LocalDateTime createTime;

    @Column(name = "valid")
    private boolean valid = true;

    public User() {
    }

    public User(String username, LocalDateTime createTime) {
        this.username = username;
        this.createTime = createTime;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", createTime=" + createTime +
                ", valid=" + valid +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public LocalDateTime getCreateTime() {
        return createTime;
    }

    public void setCreateTime(LocalDateTime createTime) {
        this.createTime = createTime;
    }

    public boolean isValid() {
        return valid;
    }

    public void setValid(boolean valid) {
        this.valid = valid;
    }
}

  Repository接口,相当于DAO接口,但是使用SpringData时建议命名为Repository而不是DAO

package org.junbin.spring.javaconfig.repository;

import org.junbin.spring.javaconfig.domain.User;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * @author : Chung Junbin
 * @email : <a href="mailto:rekadowney@163.com">发送邮件</a>
 * @createDate : 2016-09-01 21:40
 * @description :
 */
public interface UserRepository extends JpaRepository<User, Integer> {

}

  我们只需要简单声明接口即可,SpringData会自动生成相应的实现类。
  跳过Service业务类,接下来是Controller

package org.junbin.spring.javaconfig.controller;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.junbin.spring.javaconfig.converter.gson.GsonLocalDateTimeConverter;
import org.junbin.spring.javaconfig.domain.User;
import org.junbin.spring.javaconfig.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import java.time.LocalDateTime;

/**
 * @author : Chung Junbin
 * @email : <a href="mailto:rekadowney@163.com">发送邮件</a>
 * @createDate : 2016-09-01 22:01
 * @description :
 */
@Controller
@RequestMapping(value = "/user")
public class UserController {

    @Autowired
    @Qualifier(value = "userService")
    private IUserService userService;

    private final Gson gson = new GsonBuilder()
            .registerTypeAdapter(LocalDateTime.class, new GsonLocalDateTimeConverter())
            .create();

    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public ModelAndView add(@RequestParam(value = "name") String name,
                            @RequestParam(value = "createTime")
                            @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime now) {
        userService.save(new User(name, now));
        return null;
    }

    @RequestMapping(value = "/add/and/show", method = RequestMethod.GET)
    public String addRedirect(@RequestParam(value = "name") String name,
                              @RequestParam(value = "createTime")
                              @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime now) {
        User user = userService.save(new User(name, now));
        return "redirect:/user/" + user.getId() + "/show";
    }

    @RequestMapping(value = "/{id:\\d+}/delete", method = RequestMethod.GET)
    @ResponseBody
    public String delete(@PathVariable(value = "id") int id) {
        userService.delete(id);
        return "{\"status\":200}";
    }

    @RequestMapping(value = "/{id:\\d+}/show", method = RequestMethod.GET)
    @ResponseBody
    public String show(@PathVariable(value = "id") int id) {
        return gson.toJson(userService.findOne(id));
    }

    @RequestMapping(value = "/page/{pageOffset:\\d+}/{pageSize:\\d+}", method = RequestMethod.GET)
    public String page(@PathVariable(value = "pageOffset") int pageOffset,
                       @PathVariable(value = "pageSize") int pageSize,
                       Model model) {
        Pageable pageable = new PageRequest(pageOffset, pageSize);
        Page<User> userPage = userService.find(pageable);
        model.addAttribute("page", userPage);
        return "page";
    }

}

  自己在数据库中插入一些数据或者使用SpringData提供的批量插入方法或者使用上面Controller提供的GET请求插入数据后,我们访问http://localhost/user/page/0/10即可显示分页信息。如下图:
Spring+SpringMVC+SpringData+JPA.jpg


  写作本文只是对Spring知识的一个补充,基于Java配置看起来虽然很不错,但是实际上个人并不是十分推崇这种做法。
  首先,IDEA对基于Java配置的Spring处理的效果比基于XML配置的Spring差很多,比如代码提示——很多快捷的代码提示(诸如视图解析等)没有起作用;比如主动注入——我的IDEA上在注入UserRepository时提示没有找到合适的Bean;还有一些其他的问题。
  其次,HibernateJPA规范的实现厂商)对主键生成策略AUTO的实现很奇怪,明明已经指定方言为MySQL了,它依然在生成主键时依然与Hibernate自动生成的一张存储主键的表(当然,有可能是因为Hibernate5对主键生成策略的实现不同!)。见下图,自动生成了一个hibernate_sequence的表来存储user表的主键值。

基于Java配置Spring的主键生成.jpg
  最后,一些Spring的其他功能在基于Java配置时不起作用,比如自定义的PropertyEditor,当然包括Spring原生的PropertyEditor也不起作用了,因为根本就不需要用到这些配置。从另一方面也可以看成是好处。


原创声明:
本文为个人原创,如有错误与不妥,欢迎提出!
另外,未经许可,谢绝转载。

源码地址1:Git@OSC

源码地址2:GitHub

编写日期:2016-09-06
发布日期:2016-09-06
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值