本篇文章主要介绍了Spring Boot + Jpa(Hibernate) 架构基本配置详解,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
1、基于springboot-1.4.0.RELEASE版本测试
2、springBoot + hibernate + Druid + MysqL + servlet(jsp)
不废话,直接上代码
一、maven的pom文件
4.0.0com.zsxdemowar0.0.1zsx Maven Webapphttp://maven.apache.orgUTF-81.77.0.69org.springframework.bootspring-boot-starter-parent1.4.0.RELEASEOrg.apache.tomcat.embedtomcat-embed-jasperjavax.servletjstlorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-data-jpaMysqLmysql-connector-javaorg.springframework.bootspring-boot-starter-tomcatprovidedorg.springframework.bootspring-boot-devtoolscom.alibabafastjson1.2.16com.alibabadruid1.0.25org.apache.poipoi3.14org.springframework.bootspring-boot-starter-testtestio.springfoxspringfox-swagger22.6.0io.springfoxspringfox-swagger-ui2.6.0/org.springframework.bootspring-boot-maven-pluginorg.springframeworkspringloaded1.2.6.RELEASEaliali Repositoryhttp://maven.aliyun.com/nexus/content/groups/public/false
二、项目架构
想想还是介绍一下项目的目录结构,这样方便梳理整体的架构配置
src ├─main │ ├─java │ │ └─com │ │ └─zsx │ │ │ Application.java │ │ │ SpringBootStartApplication.java │ │ │ │ │ ├─common │ │ │ ├─config │ │ │ │ DruidDBConfig.java │ │ │ │ MultipartConfig.java │ │ │ │ │ │ │ ├─filter │ │ │ │ DruidStatFilter.java │ │ │ │ │ │ │ ├─interceptors │ │ │ │ AuthInterceptor.java │ │ │ │ WebAppConfigurer.java │ │ │ │ │ │ │ ├─servlet │ │ │ │ DruidStatViewServlet.java │ │ │ │ │ │ │ └─swagger │ │ │ Swagger2.java │ │ │ │ │ ├─controller │ │ │ │ LoginController.java │ │ │ │ TestController.java │ │ │ │ UserController.java │ │ │ │ │ ├─dao │ │ │ │ TUserDao.java │ │ │ │ │ │ │ └─impl │ │ ├─entity │ │ │ │ BaseEntity.java │ │ │ │ │ ├─model │ │ │ │ Tree.java │ │ │ │ │ ├─service │ │ │ │ UserService.java │ │ │ │ │ │ │ └─impl │ │ │ UserServiceImpl.java │ │ │ │ │ └─util │ │ GeneratePageable.java │ │ │ ├─resources │ │ │ application.properties │ │ │ logback-test.xml │ │ │ │ │ └─static │ │ ├─css │ │ ├─img │ │ └─js │ │ │ └─webapp │ │ index.jsp │ │ │ └─WEB-INF │ │ web.xml │ │ │ └─view │ │ login.jsp │ │ │ ├─error │ │ 500.jsp │ ├─jsp │ main.jsp │ └─test └─java UtilTest.java
标准的maven项目结构,其中Java下是dao、service、controller ,还有实体类映射entity,其他配置config
三、resources下的应用配置文件application.properties
#server.port=9090 # 数据库访问配置 # 主数据源,默认的 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.url=jdbc:MysqL://localhost:3306/test spring.datasource.username= root spring.datasource.password= root spring.datasource.driverClassName = com.MysqL.jdbc.Driver # 下面为连接池的补充设置,应用到上面所有数据源中 # 初始化大小,最小,最大 spring.datasource.initialSize=5 spring.datasource.minIdle=5 spring.datasource.maxActive=20 # 配置获取连接等待超时的时间 spring.datasource.maxWait=60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 spring.datasource.timeBetweenevictionRunsMillis=60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 spring.datasource.minevictableIdleTimeMillis=300000 spring.datasource.validationQuery=SELECT 1 FROM DUAL spring.datasource.testWhileIdle=true spring.datasource.testOnBorrow=false spring.datasource.testOnReturn=false # 打开PSCache,并且指定每个连接上PSCache的大小 spring.datasource.poolPreparedStatements=true spring.datasource.maxPoolPreparedStatementPerConnectionSize=20 # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 spring.datasource.filters=stat,wall,log4j # 通过connectProperties属性来打开mergesql功能;慢sql记录 spring.datasource.connectionProperties=druid.stat.mergesql=true;druid.stat.slowsqlMillis=5000 # 合并多个DruidDataSource的监控数据 spring.datasource.useglobalDataSourceStat=true #JPA Configuration: spring.jpa.database=MysqL # Show or not log for each sql query spring.jpa.show-sql=false spring.jpa.generate-ddl=true # Hibernate ddl auto (create, create-drop, update) spring.jpa.hibernate.ddl-auto=create #spring.jpa.database-platform=org.hibernate.dialect.MysqL5Dialect spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.ImprovednamingStrategy #spring.jpa.database=org.hibernate.dialect.MysqL5InnoDBDialect spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MysqL5Dialect spring.mvc.view.prefix=/WEB-INF/view/ spring.mvc.view.suffix=.jsp #spring.resources.static-locations=classpath:/resources/,classpath:/static/
四、启动应用主类文件 Application.java
package com.zsx; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; @SpringBootApplication @ServletComponentScan // 扫描使用注解方式的servlet public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
若需要部署到外部的tomcat容器中,则添加下面类即可。
package com.zsx; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.context.web.SpringBootServletinitializer; /** * 修改启动类,继承 SpringBootServletinitializer 并重写 configure 方法 * @author ZSX * */ public class SpringBootStartApplication extends SpringBootServletinitializer { private static final Logger logger = LoggerFactory.getLogger(SpringBootStartApplication.class); @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(Application.class); } }
五、数据库连接池Druid的配置
package com.zsx.common.config; import java.sql.sqlException; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import com.alibaba.druid.pool.DruidDataSource; /** * DruidDBConfig类被@Configuration标注,用作配置信息; * DataSource对象被@Bean声明,为spring容器所管理, * @Primary表示这里定义的DataSource将覆盖其他来源的DataSource。 * @author ZSX *jdbc.url=${jdbc.url} *最新的支持方式如下: *jdbc.url=@jdbc.url@ */ @Configuration public class DruidDBConfig { // private Logger logger = LoggerFactory.getLogger(DruidDBConfig.class); @Value("${spring.datasource.url}") private String dbUrl; @Value("${spring.datasource.username}") private String username; @Value("${spring.datasource.password}") private String password; @Value("${spring.datasource.driverClassName}") private String driverClassName; @Value("${spring.datasource.initialSize}") private int initialSize; @Value("${spring.datasource.minIdle}") private int minIdle; @Value("${spring.datasource.maxActive}") private int maxActive; @Value("${spring.datasource.maxWait}") private int maxWait; @Value("${spring.datasource.timeBetweenevictionRunsMillis}") private int timeBetweenevictionRunsMillis; @Value("${spring.datasource.minevictableIdleTimeMillis}") private int minevictableIdleTimeMillis; @Value("${spring.datasource.validationQuery}") private String validationQuery; @Value("${spring.datasource.testWhileIdle}") private boolean testWhileIdle; @Value("${spring.datasource.testOnBorrow}") private boolean testOnBorrow; @Value("${spring.datasource.testOnReturn}") private boolean testOnReturn; @Value("${spring.datasource.poolPreparedStatements}") private boolean poolPreparedStatements; @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}") private int maxPoolPreparedStatementPerConnectionSize; @Value("${spring.datasource.filters}") private String filters; @Value("{spring.datasource.connectionProperties}") private String connectionProperties; @Bean // 声明其为Bean实例 @Primary // 在同样的DataSource中,首先使用被标注的DataSource public DataSource dataSource() { DruidDataSource datasource = new DruidDataSource(); datasource.setUrl(this.dbUrl); datasource.setUsername(username); datasource.setPassword(password); datasource.setDriverClassName(driverClassName); // configuration datasource.setinitialSize(initialSize); datasource.setMinIdle(minIdle); datasource.setMaxActive(maxActive); datasource.setMaxWait(maxWait); datasource.setTimeBetweenevictionRunsMillis(timeBetweenevictionRunsMillis); datasource.setMinevictableIdleTimeMillis(minevictableIdleTimeMillis); datasource.setValidationQuery(validationQuery); datasource.setTestWhileIdle(testWhileIdle); datasource.setTestOnBorrow(testOnBorrow); datasource.setTestOnReturn(testOnReturn); datasource.setPoolPreparedStatements(poolPreparedStatements); datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize); try { datasource.setFilters(filters); } catch (sqlException e) { } datasource.setConnectionProperties(connectionProperties); return datasource; } }
springboot里默认使用tomcat的上传文件大小限制,即1MB, 修改用下面的配置类:
import javax.servlet.MultipartConfigElement; import org.springframework.boot.web.servlet.MultipartConfigFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MultipartConfig { @Bean public MultipartConfigElement multipartConfigElement(){ MultipartConfigFactory factory = new MultipartConfigFactory(); factory.setMaxFileSize("10MB"); factory.setMaxRequestSize("10MB"); return factory.createMultipartConfig(); } }
六、开启Druid的数据库监控配置
1、配置Filter
import javax.servlet.annotation.WebFilter; import javax.servlet.annotation.WebInitParam; import com.alibaba.druid.support.http.WebStatFilter; /** * 配置druid监控统计功能 * 配置Filter * @author ZSX * */ @WebFilter(filterName = "druidWebStatFilter", urlPatterns = "/*", initParams = { @WebInitParam(name="exclusions",value="*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*")// 忽略资源 } ) public class DruidStatFilter extends WebStatFilter { }
2、 配置web访问的servlet
import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; import com.alibaba.druid.support.http.StatViewServlet; /** * 配置druid监控统计功能 * 在SpringBoot项目中基于注解的配置,如果是web.xml配置,按规则配置即可 * @author ZSX * */ @WebServlet(urlPatterns = "/druid/*", initParams = { // @WebInitParam(name = "allow", value = "192.168.16.110,127.0.0.1"), // IP白名单 (没有配置或者为空,则允许所有访问) // @WebInitParam(name="deny",value="192.168.16.111"), // IP黑名单 (存在共同时,deny优先于allow) @WebInitParam(name="loginUsername",value="druid"),// 用户名 @WebInitParam(name="loginPassword",value="druid"),// 密码 @WebInitParam(name="resetEnable",value="false")// 禁用HTML页面上的“Reset All”功能 } ) public class DruidStatViewServlet extends StatViewServlet { }
这样启动项目后在浏览器中输入地址:端口/druid,就可以看到druid的监控web页面了
七、 拦截器配置
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration public class WebAppConfigurer extends WebMvcConfigurerAdapter { /** * 配置拦截器 */ @Override public void addInterceptors(InterceptorRegistry registry) { // Todo Auto-generated method stub // 多个拦截器组成一个拦截器链 // addpathPatterns 用于添加拦截规则 // excludePathPatterns 用户排除拦截 registry.addInterceptor(new AuthInterceptor()).addpathPatterns("/**"); super.addInterceptors(registry); } /** * 添加自定义的静态资源映射 这里使用代码的方式自定义目录映射,并不影响Spring Boot的默认映射,可以同时使用。 */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // registry.addResourceHandler("/new/**").addResourceLocations("classpath:/new/"); // registry.addResourceHandler("/**").addResourceLocations("/"); super.addResourceHandlers(registry); } }
八、swagger发布api测试配置(可忽略)
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 public class Swagger2 { @Bean public Docket createRestApi(){ return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.zsx.controller.api")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo(){ return new ApiInfoBuilder() .title("Spring Boot中使用Swagger2构建RESTful APIs") .description("描述") .termsOfServiceUrl("http://zsx.com.cn") .version("1.0") .build(); } }
至此,所有的配置已完成,下面是一个操作数据的简单demo
九、实体类
@Entity @Table(name = "t_user") public class Tuser implements java.io.Serializable { /** * */ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; @Column(name = "username") private String userName; @Column(name = "password") private String passWord; @Column(name = "email") private String email; @Column(name = "mobile") private String mobile; @Column(name = "nickname") private String nickName; // 省略getter 和 setter }
十、dao层
1、使用jpa基本可以实现不写sql,(但实际开发中,业务逻辑会很复杂,一点不写sql完全不现实)
2、注意添加@Repository注解, 添加JpaSpecificationExecutor继承可以方便分页
3、 看些jpa的查询语法资料
import java.util.List; import java.util.Map; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @Repository public interface TuserDao extends PagingAndSortingRepository, JpaSpecificationExecutor { Tuser findByUserName(String userName); @Query("from Tuser t where id = :id") List queryFamilyList(@Param("id") Long id, Pageable pageable); }
十一、service和controller没啥好说的,跟原先的一样,下面再提供一个单元测试的demo
import java.util.List; import javax.persistence.EntityManager; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import com.alibaba.fastjson.JSON; import com.golden.Application; import com.golden.dao.TUserDao; import com.golden.entity.Tuser; import com.golden.util.GeneratePageable; @RunWith(SpringJUnit4ClassRunner.class) //指定我们SpringBoot工程的Application启动类 @SpringApplicationConfiguration(classes = Application.class) //由于是Web项目,Junit需要模拟ServletContext,因此我们需要给我们的测试类加上@WebAppConfiguration @WebAppConfiguration public class UtilTest { @Autowired private TUserDao dao; @Autowired private EntityManager em; @Test public void test1(){ dao.findByUserName("admin"); } @Test public void test2(){ // 使用jpa提供的分页类 java.util.List list = new ArrayList(); Order order = new Order(Direction.DESC, "createTime"); list.add(order); Sort sort = new Sort(list); Pageable pageable = new PageRequest(0, 10, sort); Page findAll = dao.findAll(pageable); } @Test public void test3(){ EntityManager em = dao.getEntityManager(); Query query = em.createNativeQuery("select * from t_user limit 1"); Object singleResult = query.getSingleResult(); System.out.println(singleResult); } /* //执行原生sql Query nativeQuery = em.createNativeQuery(String sql); //指定返回对象类型 nativeQuery.unwrap(sqlQuery.class).setResultTransformer(Transformers.aliasToBean( Class resultType)); //返回对象 List resultList = nativeQuery.getResultList(); */ }
后记:
不用Druid的可以把有关Druid的配置全部删掉,swagger的同理
这里没有使用hibernate.cfg.xml配置文件,主要习惯了在实体类里配置字段了,不怎么用hibernate的映xml文件了,但其实配置起来跟springmvc项目一样
说实话这里使用jpa操作数据库,没感觉有多方便,因为总有各种奇葩的需求,当然也可能是我没深入研究,所以建议改用Mybatis,这个我会再写一篇springboot加mybatis的配置教程的,最后,还可以使用原生的SQL查询,即使用单元测试里的EntityManager对象去执行sql,返回结果可以指定对象类型,也很方便
还需要注意的一个点是静态文件的存放位置,这个跟原先的项目不一样,原先是在webapp下,但springboot是默认放在resources下的static目录下的,还有其他默认目录和配置,自行搜索