背景:

  有需求要将原来的Spring(3.2.6) + Springmvc + Hibernate项目重构为Springboot(1.5.2)项目

描述:

  记录重构过程,以及期间遇到的种种问题和对应的解决方案  

环境:

  原项目: win10 + eclipse + jdk1.8 + mysql5.7

  新项目: win10 + IDEA + jdk1.8 + mysql5.7 + Maven

过程:

  第一步:  新建Maven项目

    IDEA: project > New > Module > Maven (选择 maven-archetype-quickstart 快速创建一个maven项目, 如下图)

    

    点击Next, 自己想一个项目的 groupid(一般为项目域名的倒写) 和 artifactid(项目名) 并填好(如下图)

    

    点击Next, 确认创建信息

    点击Next, 选择项目创建文件夹地址

    点击确认自动创建项目

    项目创建就完成了

    如果发现创建maven项目十分缓慢, 很可能是由于访问maven官方中央仓库网速太差导致的,建议可以修改Maven的settings.xml文件

    将默认的仓库地址改为国内阿里云的地址(http://maven.aliyun.com/nexus/content/groups/public/),(如下图)

    

   第二步: 配置pom.xml

     不多说,上代码,如果对其中某些节点含义不清楚, 可以参考此博文: https://www.cnblogs.com/hafiz/p/5360195.html

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.yjy.test</groupId><version>1.0-SNAPSHOT</version><artifactId>yjyboot-${project.version}</artifactId><name>yjyboot</name><packaging>war</packaging><properties><java.version>1.8</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><log4j2.level>debug</log4j2.level><log4j2.root.path>/logs/${project.name}</log4j2.root.path><log4j2.error.path>/logs/${project.name}-error</log4j2.error.path><log4j2.package.path>/logs/${project.name}-kk</log4j2.package.path></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.2.RELEASE</version></parent><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!--https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-log4j2--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId></dependency><!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-web --><!-- 如果没有此 log4j-web 导出的war将不能打印日志到文件!!! --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-web</artifactId><version>2.7</version></dependency><!-- freemarker --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><!-- 下面两个引入为了操作数据库 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- Json包 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.16</version></dependency><!-- 为了监控数据库 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.0.25</version></dependency><!-- commons --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.7</version></dependency><!-- httpclient --><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpmime</artifactId><version>4.5.3</version></dependency><!-- https://mvnrepository.com/artifact/commons-httpclient/commons-httpclient --><dependency><groupId>commons-httpclient</groupId><artifactId>commons-httpclient</artifactId><version>3.1</version></dependency><dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</artifactId></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.5</version></dependency><!-- 兼容log4j --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-1.2-api</artifactId><version>2.8.2</version></dependency><!-- Redis --><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId></dependency><!-- https://mvnrepository.com/artifact/nl.bitwalker/UserAgentUtils --><dependency><groupId>nl.bitwalker</groupId><artifactId>UserAgentUtils</artifactId><version>1.2.4</version></dependency><!--打war包时加入此项 告诉spring-boot tomcat相关jar包用外部的 不要打进去IDEA运行时需要将此依赖注释掉, 否则会无法运行--><!--<dependency>--><!--<groupId>org.springframework.boot</groupId>--><!--<artifactId>spring-boot-starter-tomcat</artifactId>--><!--<scope>provided</scope>--><!--</dependency>--></dependencies><build><finalName>${project.name}</finalName><directory>target</directory><sourceDirectory>src/main/java</sourceDirectory><testSourceDirectory>src/test/java</testSourceDirectory><outputDirectory>target</outputDirectory><resources><resource><directory>src/main/resources</directory><filtering>true</filtering><includes><include>**/*</include></includes></resource><!-- 将自定义的Servlet(extends DispatcherServlet)默认xml配置文件打包至WEB-INF下否则外部tomcat无法处理此Servlet --><resource><directory>src/main/extraConfig</directory><targetPath>${build.finalName}/WEB-INF/</targetPath></resource></resources><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><executions><execution><goals><goal>build-info</goal></goals></execution></executions></plugin><!--spring-boot为了保护application.yml和application.properties,修改了默认的占位符${...}为@...@--><!--为了spring boot的yml和properties文件能够使用maven变量替换,使用${}占位符--><plugin><artifactId>maven-resources-plugin</artifactId><configuration><encoding>utf-8</encoding><useDefaultDelimiters>true</useDefaultDelimiters></configuration></plugin></plugins></build></project>

pom.xml

  

   第三步: 创建配置文件, 特别注意:  log4j2.xml 只能放在resources目录下, 否则导出的war包,配置的log4j2将不起作用!!!!

    

spring:profiles:active: dev # 激活的配置文件include: freemarker,mysql,redis,interceptor # 加载其他配置文件mvc:favicon:enabled: truedebug: true # 是否启用debugserver:servlet-path: /common # 所有接口请求都交由自定义的Servlet处理了, 所以默认的servlet只用于处理静态资源

application.yml

spring:freemarker:enabled: true # 是否启用freemarkercache: false # 是否启用缓存prefix: # 模板文件前缀suffix: .ftl # 模板文件后缀charset: UTF-8 # 模板文件编码template-loader-path: classpath:templates/ # 模板文件目录check-template-location: true # 是否检查模板目录是否存在content-type: text/html # 模板类型request-context-attribute: req # RequestContext 引用settings: # 更多配置number_format: '0.##'  #数字格式化, 保留两位小数allow-request-override: false # 是否允许 request 属性覆盖 controller 属性allow-session-override: false # 是否允许 session 属性覆盖 controller 属性expose-request-attributes: false # 设置在与模板合并之前,是否应该将所有HttpRequest属性添加到模型中。expose-session-attributes: false # 设置在与模板合并之前,是否应该将所有HttpSession属性添加到模型中。expose-spring-macro-helpers: true # 设置是否公开一个请求上下文,以供Spring的宏库使用,名称为“springMacroRequestContext”prefer-file-system-access: true # 更喜欢文件系统访问模板加载。文件系统访问支持对模板更改进行热检测。
#    view-names: # whitelist of view names that can be resolved

application-freemarker.yml

front:login:excludeUrls: # 这里配置的前台登入验证的白名单- /hello.sv- /hello2.sv- /index.jtk- /autho.jtk- /code.jtk- /checkLogin.jtk- /checkUser.jtk- /test.jtk- /wxPay/notify.jtk- /api/list.jtk- /api/deposit.jtk- /config/wechat.jtkback:login:excludeUrls: # 这里配置的后台登入验证的白名单- /login.do- /logout.do- /game/scores.do- /game/dayScore.do

application-interceptor.yml

spring:datasource:# 数据库访问配置# 主数据源,默认的type: com.alibaba.druid.pool.DruidDataSourcedbUrl: jdbc:mysql://localhost:3306/hotpot?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: yjypassword: yyyyyydriverClassName: com.mysql.jdbc.Driver# 下面为连接池的补充设置,应用到上面所有数据源中# 初始化大小,最小,最大initialSize: 5minIdle: 5maxActive: 20maxWait: 60000 # 配置获取连接等待超时的时间timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: true # 打开PSCache,并且指定每个连接上PSCache的大小maxPoolPreparedStatementPerConnectionSize: 20filters: stat,wall,log4j # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 # 通过connectProperties属性来打开mergeSql功能;慢SQL记录useGlobalDataSourceStat: true # 合并多个DruidDataSource的监控数据#JPA Configuration:jpa:database: MYSQLshow-sql: true # Show or not log for each sql querygenerate-ddl: true # Hibernate ddl auto (create, create-drop, update)hibernate:ddl-auto: updatenaming:strategy: org.hibernate.cfg.ImprovedNamingStrategyproperties:hibernate:dialect: org.hibernate.dialect.MySQL5Dialect

application-mysql.yml

<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration status="INFO" monitorInterval="30"><!--先定义所有的appender--><appenders><!--这个输出控制台的配置--><console name="Console" target="SYSTEM_OUT"><!--输出日志的格式--><PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/><!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)--><ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/></console><!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用--><File name="CurrentLog" fileName="logs/current.log" append="false"><PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/></File><!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档--><RollingFile name="RollingFileInfo" fileName="F:/logs/info.log"filePattern="F:/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log"><!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)--><ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/><PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/><Policies><TimeBasedTriggeringPolicy/><SizeBasedTriggeringPolicy size="50MB"/></Policies></RollingFile><RollingFile name="RollingFileWarn" fileName="F:/logs/warn.log"filePattern="F:/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log"><ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/><PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/><Policies><TimeBasedTriggeringPolicy/><SizeBasedTriggeringPolicy size="30MB"/></Policies><!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 --><DefaultRolloverStrategy max="20"/></RollingFile><RollingFile name="RollingFileError" fileName="F:/logs/error.log"filePattern="F:/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log"><ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/><PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/><Policies><TimeBasedTriggeringPolicy/><SizeBasedTriggeringPolicy size="20MB"/></Policies></RollingFile></appenders><!--然后定义logger,只有定义了logger并引入的appender,appender才会生效--><loggers><!--过滤掉spring和mybatis的一些无用的DEBUG信息--><logger name="org.springframework" level="INFO"/><logger name="org.springframework.boot.autoconfigure.logging" level="INFO"/><logger name="org.springframework.boot.logging" level="INFO"/><logger name="org.mybatis" level="INFO"/><logger name="org.hibernate" level="INFO"/><logger name="druid.sql" level="INFO"/><root level="info"><appender-ref ref="Console"/><appender-ref ref="CurrentLog"/><appender-ref ref="RollingFileInfo"/><appender-ref ref="RollingFileWarn"/><appender-ref ref="RollingFileError"/></root></loggers>
</configuration>

log4j2.xml

server:port: 8082 # 嵌入server的运行端口context-path: /yjyboot # 配置项目运行地址
spring:devtools:restart:exclude: classpath:common/**,classpath:templates/**

application-dev.yml

server:port: 8080context-path: /yjyboot # 导出war包存放在tomcat后会有一个项目运行地址, 这里配置可以模拟项目地址, 达到IDEA运行与tomcat运行地址相同

application-pro.yml

  第四步: 主类(一般放在根包中)

    

package com.yjy.test;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;/*** SpringBoot 启动入口** @Author yjy* @Date 2018-04-17 12:43*/
//@SpringBootApplication = (@Configuration, @EnableAutoConfiguration, @ComponentScan)
@Configuration
@EnableAutoConfiguration
@ComponentScan
@EntityScan("com.yjy.test.game.entity") // 扫描实体类
@ServletComponentScan(basePackages = "com.yjy.test") // 扫描自定义Servlet
@PropertySource(value = { // 导入配置"classpath:/config/application.yml",
})
public class Application extends SpringBootServletInitializer {// IDEA运行时 运行此函数public static void main(String[] args) {SpringApplication.run(Application.class, args);}// 导出war在外部tomcat使用时, 不能使用main函数运行, 需要配置此项
    @Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(Application.class);}}

    第五步: 添加配置类(按自己的需要添加, 无特别说明的情况下, 配置类可以存在任意包内, 只需满足包级别不高于Application.java所在的包就可以

      当然也可以通过配置扫描包注解来自定义, 默认扫描主类所在包以下的所有包)

      1: 全局跨域配置类(放在与Application.java同目录下)

package com.yjy.test;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;/*** 跨域配置** @Author yjy* @Date 2018-04-26 15:55*/
@Configuration
public class CorsConfig {private CorsConfiguration buildConfig() {CorsConfiguration corsConfiguration = new CorsConfiguration();corsConfiguration.addAllowedHeader("*");corsConfiguration.addAllowedMethod("*");corsConfiguration.addAllowedOrigin("*");corsConfiguration.setAllowCredentials(true);return corsConfiguration;}@Beanpublic CorsFilter corsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", buildConfig());return new CorsFilter(source);}}

跨域配置

      2: Date参数的格式化( 请求中符合格式的字符串参数可以使用Date类型接收参数, 比如请求参数 ?addTime=20180101, Controller层可以使用 func(Date addTime); 接收, 否则会报400错误)

package com.yjy.test;import org.apache.commons.lang3.StringUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;import java.text.ParseException;
import java.text.SimpleDateFormat;/*** Date参数格式化** 尝试格式化java.util.Date类型的参数** @Author yjy* @Date 2018-04-27 9:58*/
@Component
public class DateConverterConfig implements Converter<String, java.util.Date> {private static final String[] formats = new String[] {"yyyy-MM-dd", // 0"yyyy-MM", // 1"yyyy-MM-dd HH:mm:ss", // 2"yyyy-MM-dd HH:mm", // 3
    };/*** 这里将参数格式化成 java.sql.Date 为了方便后面用来拼接sql* @param param 日期格式的字符串* @return java.sql.Date*/@Overridepublic java.sql.Date convert(String param) {if (StringUtils.isBlank(param)) {return null;}param = param.trim();if (param.matches("^\\d{4}-\\d{1,2}-\\d{1,2}$")) {return parseDate(param, formats[0]);}if (param.matches("^\\d{4}-\\d{1,2}$")) {return parseDate(param, formats[1]);}if (param.matches("^\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}$")) {return parseDate(param, formats[2]);}if (param.matches("^\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}$")) {return parseDate(param, formats[3]);}throw new IllegalArgumentException("Invalid date param '" + param + "'");}/*** 格式化日期* @param dateStr 日期字符串* @param format 格式* @return 日期*/private java.sql.Date parseDate(String dateStr, String format) {java.sql.Date date = null;try {SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);java.util.Date dates = simpleDateFormat.parse(dateStr);date = new java.sql.Date(dates.getTime());} catch (ParseException e) {e.printStackTrace();}return date;}}

日期参数格式化配置

      3: 自定义指定请求前缀的Servlet(一个前台, 一个后台)

package com.yjy.test.game.web.servlet;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 后台servlet* 需要添加对应的 *-servlet.xml** @Author yjy* @Date 2018-04-23 16:26*/
@WebServlet(name = "backServlet", urlPatterns = {"/manager/admin/*"})
public class CustomBackServlet extends DispatcherServlet {private static final Logger log = LoggerFactory.getLogger(CustomBackServlet.class);@Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {log.info("backServlet doService...");super.doService(request, response);}}

后台自定义Servlet

package com.yjy.test.game.web.servlet;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 前台servlet* 需要添加对应的 *-servlet.xml** @Author yjy* @Date 2018-04-23 16:26*/
@WebServlet(name = "frontServlet", urlPatterns = {"/*"})
public class CustomFrontServlet extends DispatcherServlet {private static final Logger log = LoggerFactory.getLogger(CustomFrontServlet.class);@Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {log.info("frontServlet doService...");super.doService(request, response);}}

前台自定义Servlet

      对应的默认xml文件, 打包war的时候需要, 看pom.xml中相应配置, 否则到外部tomcat运行时, 会报找不到对应的配置文件的错误

      

      xml内容都是一样的

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 此文件用于项目导出war包在外部tomcat运行时检测, 如果没有此文件, 则自定义Servlet无法访问 --></beans>

自定义Servlet默认配置

      4: 因为上面两个自定义的Servlet继承自DispatcherServlet, 不允许重写init()方法, 所以如果需要自定义初始化ServletContext, 则必须自己写一个Servlet继承HttpServlet,( 此Servlet不需要配置相应的xml文件)

package com.yjy.test.game.web.servlet;import com.yjy.test.game.service.OptionItemService;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;/*** 自定义初始化 ServletContext** WebServlet中 urlPatterns必须填写, 否则不会加载此Servlet, 同时需要配置 loadOnStartup = 1** @Author yjy* @Date 2018-05-02 11:47*/
@WebServlet(urlPatterns = "", loadOnStartup = 1)
public class DictServlet extends HttpServlet {private OptionItemService optionItemService;public void setOptionItemService(OptionItemService optionItemService) {this.optionItemService = optionItemService;}public void init() throws ServletException {System.out.println("DictServlet init..............................");WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(this.getServletContext());setOptionItemService(wac.getBean (OptionItemService.class));optionItemService.getAllFieldName();// init something...// 例子: 设置Servlet全局属性this.getServletContext().setAttribute("appName", "项目名");super.init();}}

初始化ServletContext

      5: 静态资源请求配置

package com.yjy.test.config;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;/*** 自定义WebMvcConfigurerAdapter配置** @Author yjy* @Date 2018-04-23 11:40*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {private static final Logger log = LoggerFactory.getLogger(WebMvcConfig.class);/*** 静态资源请求配置* @param registry 资源处理注册器*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {log.info("addResourceHandlers...........................");registry.addResourceHandler("/**").addResourceLocations("classpath:/common/");super.addResourceHandlers(registry);}}

静态资源配置

      6: tomcat上传配置

package com.yjy.test.config;import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.MultipartConfigElement;/*** 配置tomcat上传限制** @Author yjy* @Date 2018-04-24 14:38*/
@Configuration
public class MultipartConfig {/*** 配置tomcat上传限制* @return 配置*/@Beanpublic MultipartConfigElement multipartConfigElement(){MultipartConfigFactory factory = new MultipartConfigFactory();factory.setMaxFileSize("50MB");factory.setMaxRequestSize("10MB");return factory.createMultipartConfig();}}

上传配置

      7: 前后台登入拦截器, 以及相应配置类

package com.yjy.test.game.web.interceptor;import com.yjy.test.game.entity.Config;
import com.yjy.test.game.entity.User;
import com.yjy.test.game.service.ConfigService;
import com.yjy.test.game.util.FrontUtils;
import com.yjy.test.game.web.ErrorCode;
import com.yjy.test.util.UnicodeUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.util.UrlPathHelper;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;/*** 前台登入拦截器** @Author yjy* @Date 2018-04-24 15:03*/
// 这里导入前缀为 front.login 的配置参数
@ConfigurationProperties(prefix = "front.login")
public class FrontLoginInterceptor extends HandlerInterceptorAdapter {private static final Logger log = LoggerFactory.getLogger(FrontLoginInterceptor.class);// 例外private List<String> excludeUrls = new ArrayList<>();private ConfigService configService;@Autowiredpublic void setConfigService(ConfigService configService) {this.configService = configService;}@Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {log.info("FrontLoginInterceptor > excludeUrls: {}", excludeUrls);String uri = getURI(request);if (exclude(uri)) {return true;}try {request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");User user = FrontUtils.getCurrentUser(request);if (null == user) {Enumeration s = request.getHeaderNames();String requestType = request.getHeader("X-Requested-With");if (requestType != null && requestType.equals("XMLHttpRequest")) {response.setCharacterEncoding("UTF-8");response.setContentType("application/json; charset=utf-8");response.getOutputStream().print("{\"status\":0,\"info\":\""+ UnicodeUtil.toEncodedUnicode( "登录超时,请重新登录", false)+ "\", \"data\":null, \"code\": \"" + ErrorCode.ER_NOT_LOGIN + "\"}" );return false;}Config config = configService.findThisConfig();String path = null;if(null != config){path = StringUtils.isNotBlank(request.getContextPath()) ? request.getContextPath():"";}String reLogin = "/autho.jtk";if(StringUtils.isNotBlank(path) && path.length() > 1) {reLogin = path + reLogin;}response.sendRedirect(reLogin);return false;}} catch (Exception e) {log.error("检查前台登录参数出错", e);}return super.preHandle(request, response, handler);}private boolean exclude(String uri) {if (excludeUrls != null) {for (String exc : excludeUrls) {if (exc.equals(uri)) {return true;}}}return false;}/*** 获得第三个路径分隔符的位置** @param request* @throws IllegalStateException*             访问路径错误,没有三(四)个'/'*/private static String getURI(HttpServletRequest request)throws IllegalStateException {UrlPathHelper helper = new UrlPathHelper();String uri = helper.getOriginatingRequestUri(request);return uri;}public List<String> getExcludeUrls() {return excludeUrls;}public void setExcludeUrls(List<String> excludeUrls) {this.excludeUrls = excludeUrls;}public ConfigService getConfigService() {return configService;}
}

前台登入拦截

package com.yjy.test.game.web.interceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import com.yjy.test.game.entity.Admin;
import com.yjy.test.game.entity.Config;
import com.yjy.test.game.service.ConfigService;
import com.yjy.test.game.util.BackUtils;
import com.yjy.test.game.util.UnicodeUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.util.UrlPathHelper;import java.util.ArrayList;
import java.util.List;/*** 后台上下文登录检测** @author wdy* @version :2016年2月29日 下午6:22:56*/
// 这里导入前缀为 back.login 的配置参数
@ConfigurationProperties(prefix = "back.login")
public class AdminLoginInterceptor extends HandlerInterceptorAdapter {private static final Logger log = LoggerFactory.getLogger(AdminLoginInterceptor.class);// 例外private List<String> excludeUrls = new ArrayList<>();private ConfigService configService;@Autowiredpublic void setConfigService(ConfigService configService) {this.configService = configService;}@Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {String uri = getURI(request);if (exclude(uri)) {return true;}try {request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");Admin user = BackUtils.getCurrentUser(request);if (null == user) {String requestType = request.getHeader("X-Requested-With");if (requestType != null && requestType.equals("XMLHttpRequest")) {response.setCharacterEncoding("UTF-8");response.setContentType("application/json; charset=utf-8");response.getOutputStream().print("{\"status\":2, \"code\":\"login\", \"info\":\""+ UnicodeUtil.toEncodedUnicode("登录超时,请重新登录", false)+ "\", \"data\":null}");return false;}Config config = configService.findThisConfig();String path = null;if (null != config) {path = StringUtils.isNotBlank(request.getContextPath()) ? request.getContextPath() : "";}String reLogin = "/manager/admin/login.do";if (StringUtils.isNotBlank(path) && path.length() > 1) {reLogin = path + reLogin;}response.sendRedirect(reLogin);return false;}} catch (Exception e) {log.error("检查后台登录参数出错", e);}return super.preHandle(request, response, handler);}private boolean exclude(String uri) {if (excludeUrls != null) {for (String exc : excludeUrls) {if (exc.equals(uri)) {return true;}}}return false;}/*** 获得第三个路径分隔符的位置** @param request* @throws IllegalStateException 访问路径错误,没有三(四)个'/'*/private static String getURI(HttpServletRequest request)throws IllegalStateException {UrlPathHelper helper = new UrlPathHelper();String uri = helper.getOriginatingRequestUri(request);String ctxPath = helper.getOriginatingContextPath(request);int start = 0, i = 0, count = 2;if (!StringUtils.isBlank(ctxPath)) {count++;}while (i < count && start != -1) {start = uri.indexOf('/', start + 1);i++;}if (start <= 0) {throw new IllegalStateException("admin access path not like '/manager/admin/...' pattern: "+ uri);}return uri.substring(start);}public List<String> getExcludeUrls() {return excludeUrls;}public void setExcludeUrls(List<String> excludeUrls) {this.excludeUrls = excludeUrls;}public ConfigService getConfigService() {return configService;}
}

后台登入拦截

package com.yjy.test.game.web.config;import com.yjy.test.game.web.interceptor.AdminLoginInterceptor;
import com.yjy.test.game.web.interceptor.FrontLoginInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;/*** 自定义WebMvcConfigurerAdapter配置** @Author yjy* @Date 2018-04-23 11:40*/
@Configuration
public class GameWebMvcConfig extends WebMvcConfigurerAdapter {private static final Logger log = LoggerFactory.getLogger(GameWebMvcConfig.class);/*** 拦截器配置* @param registry 拦截器注册器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {log.info("addInterceptors1....................");registry.addInterceptor(getFrontLoginInterceptor()).addPathPatterns("*.jtk", "/*.jtk", "/*/*.jtk", "/*/*/*.jtk");registry.addInterceptor(getAdminLoginInterceptor()).addPathPatterns("*.do", "/*.do", "/*/*.do", "/*/*/*.do");super.addInterceptors(registry);}@BeanAdminLoginInterceptor getAdminLoginInterceptor() {return new AdminLoginInterceptor();}@BeanFrontLoginInterceptor getFrontLoginInterceptor() {return new FrontLoginInterceptor();}}

拦截器配置类

      

     8: 添加过滤器

package com.yjy.test.game.web.filter;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** 记录请求执行时间*/
@WebFilter(urlPatterns = "/*")
public class ProcessTimeFilter implements Filter {protected final Logger log = LoggerFactory.getLogger(ProcessTimeFilter.class);/*** 请求执行开始时间*/public static final String START_TIME = "_start_time";public void destroy() {}public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) req;long time = System.currentTimeMillis();log.info("process start at {} for uri: {}", time, request.getRequestURI());request.setAttribute(START_TIME, time);chain.doFilter(request, response);time = System.currentTimeMillis() - time;log.info("process in {} ms: {}", time, request.getRequestURI());}public void init(FilterConfig arg0) throws ServletException {log.info("CustomFilter: ProcessTimeFilter init....");}}

请求执行时间过滤器

    

    第六步: 迁移原项目源码 几个遇到问题的点:

      1: hibernate -> hibernate + JPA

      原来的 *-hbm.xml 映射方式全部需要改成注解的方式, 实体类注解子如下:

package com.yjy.test.game.entity.club;import com.yjy.test.base.BaseEntity;import javax.persistence.*;
import java.math.BigInteger;
import java.util.Date;/*** 俱乐部消息表** @author yjy* Created on 2017年12月6日 上午9:34:07*/
@Entity
@Table(name = "cg_club_message")
public class ClubMessage extends BaseEntity {private static final long serialVersionUID = -1353909238958898740L;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id; // idprivate Long receiveId; // 消息接收人private Long sendId; // 消息发送人private Long clubId; // 俱乐部idprivate Long clubUserId; // 相关成员idprivate Integer type; // 类型private Integer status; // 已操作/已读状态private Integer result; // 申请结果private String remark; // 备注private Integer isDelete; // 是否删除private Date addTime; // 创建时间private Date updateTime; // 更新时间
@ManyToOne@JoinColumn(name = "clubId", insertable = false, updatable = false,foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT ))private ClubUser clubUser;// 非持久化字段
    @Transientprivate String nickName; // 昵称
    @Transientprivate String headImg; // 头像
    @Transientprivate String userCode; // 用户code
    @Transientprivate String clubName; // 俱乐部名称public ClubMessage() {}public ClubMessage(Long sendId, Long receiveId, Long clubId, Long clubUserId, Integer type) {this.sendId = sendId;this.receiveId = receiveId;this.clubId = clubId;this.clubUserId = clubUserId;this.type = type;this.init();}private void init() {this.isDelete = NO;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public Long getReceiveId() {return receiveId;}public void setReceiveId(Long receiveId) {this.receiveId = receiveId;}public Long getSendId() {return sendId;}public String getNickName() {return nickName;}public Long getClubId() {return clubId;}public Integer getIsDelete() {return isDelete;}public void setIsDelete(Integer isDelete) {this.isDelete = isDelete;}public void setClubId(Long clubId) {this.clubId = clubId;}public void setNickName(String nickName) {this.nickName = nickName;}public String getHeadImg() {return headImg;}public void setHeadImg(String headImg) {this.headImg = headImg;}public String getUserCode() {return userCode;}public void setUserCode(String userCode) {this.userCode = userCode;}public String getClubName() {return clubName;}public void setClubName(String clubName) {this.clubName = clubName;}public void setSendId(Long sendId) {this.sendId = sendId;}public Long getClubUserId() {return clubUserId;}public void setClubUserId(Long clubUserId) {this.clubUserId = clubUserId;}public ClubUser getClubUser() {return clubUser;}public void setClubUser(ClubUser clubUser) {this.clubUser = clubUser;}public Integer getType() {return type;}public void setType(Integer type) {this.type = type;}public Integer getStatus() {return status;}public void setStatus(Integer status) {this.status = status;}public Integer getResult() {return result;}public void setResult(Integer result) {this.result = result;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}public Date getAddTime() {return addTime;}public void setAddTime(Date addTime) {this.addTime = addTime;}public Date getUpdateTime() {return updateTime;}public void setUpdateTime(Date updateTime) {this.updateTime = updateTime;}@Overridepublic String toString() {return "ClubMessageDao [id=" + id + ", receiveId=" + receiveId+ ", sendId=" + sendId + ", clubId=" + clubId + ", clubUserId="+ clubUserId + ", type=" + type + ", status=" + status+ ", result=" + result + ", remark=" + remark + ", isDelete="+ isDelete + ", addTime=" + addTime + ", updateTime="+ updateTime + ", nickName=" + nickName + ", headImg="+ headImg + ", userCode=" + userCode + ", clubName=" + clubName+ "]";}}

实体类例子

package com.yjy.test.base;import java.io.Serializable;/*** 实体类父类*/
public class BaseEntity extends BaseClass implements Serializable {}

BaseEntity

package com.yjy.test.base;import org.apache.commons.lang3.StringUtils;public abstract class BaseClass {protected static final int YES = 1;protected static final int NO = 0;/*** 验证字符串* @param s 字符串* @return 是否为空*/protected static boolean isBlank(String s) {return StringUtils.isBlank(s);}/*** 验证字符串* @param s 字符串* @return 是否不为空*/protected static boolean notBlank(String s) {return StringUtils.isNotBlank(s);}/*** 验证字符串* @param s 字符串* @return 是否数字*/protected static boolean isNumber(String s) {return StringUtils.isNumeric(s);}}

BaseClass

    2: 重写Base层(代码如下),注意: 原来BaseDaoImpl中的 sessionFactory 没有了, 就是说不能通过getSession().createSQLQuery(sql) 的方式获取SQLQuery了, 需要通过em.createNativeQuery(sql).unwrap(SQLQuery.class); 来获得SQLQuery, em在BaseServiceImpl中已经注入, 通过这种方式可以兼容之前的代码

package com.yjy.test.base;import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.NoRepositoryBean;import java.io.Serializable;/*** BaseJpaRepository** @Author yjy* @Date 2018-04-25 15:55*/
@NoRepositoryBean
public interface BaseJpaRepository<T extends BaseEntity, L extends Serializable> extends JpaRepository<T, L> {public T findTopByOrderByIdDesc();}

BaseJpaRepository.java

package com.yjy.test.base;import com.yjy.test.util.hibernate.Pagination;
import org.springframework.data.domain.Sort;import java.io.Serializable;
import java.util.List;public interface BaseService<T extends BaseEntity, L extends Serializable> {/*** 保存对象** @param entity 实体对象* @return 操作信息*/T save(T entity);T update(T entity);void delete(T entity);/*** 根据ID删除记录** @param id 记录ID*/void deleteById(L id);/*** 根据ID数组删除记录,当发生异常时,操作终止并回滚** @param ids 记录ID数组* @return 删除的对象*/void deleteById(L[] ids);/*** 保存并刷新对象,避免many-to-one属性不完整** @param entity*/T saveAndRefresh(T entity);/*** 通过ID查找对象** @param id 记录的ID* @return 实体对象*/T findById(L id);T load(L id);T findByProperty(String property, Object value);List<T> findListByProperty(String property, Object value);/*** 根据属性查找* @param propertyName 属性* @param value 值* @param anywhere 是否模糊匹配* @return*/List<T> findListByProperty(String propertyName, Object value, boolean anywhere);/*** 查找所有对象** @return 对象列表*/List<T> findAll();/*** 分页查询* @param pageNo 页号* @param pageSize 条数* @param orders 排序规则* @return 分页列表*/Pagination findAllPage(int pageNo, int pageSize, Sort.Order... orders);List<T> findList(T entity, Sort.Order... orders);List<T> findList(T entity, int pageNo, int pageSize, Sort.Order... orders);Pagination findListPage(T entity, int pageNo, int pageSize, Sort.Order... orders);T findLast();T findFirst(T entity, Sort.Order... orders);long findAllCount();long findCount(T entity);}

BaseService

package com.yjy.test.base;import com.yjy.test.util.hibernate.Finder;
import com.yjy.test.util.hibernate.Pagination;
import org.hibernate.Query;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.repository.JpaRepository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;// 这里不能加@Service注解, 否则会无法获取泛型T的Class
public class BaseServiceImpl<T extends BaseEntity, L extends Serializable>extends BaseClass implements BaseService<T, L> {//@Autowired和@PersistenceContext注解任取一
    @PersistenceContextprotected EntityManager em;@Overridepublic T save(T entity) {return dao.save(entity);}@Overridepublic T update(T entity) {return dao.saveAndFlush(entity);}@Overridepublic void delete(T entity) {dao.delete(entity);}@Overridepublic void deleteById(L id) {dao.delete(id);}@Overridepublic void deleteById(L[] ids) {if (ids != null) {for (L id : ids) {dao.delete(id);}}}@Overridepublic T saveAndRefresh(T entity) {return dao.saveAndFlush(entity);}@Overridepublic T findById(L id) {return dao.findOne(id);}@Overridepublic T load(L id) {return dao.getOne(id);}@Overridepublic T findByProperty(String property, Object value) {List<T> list = findListByProperty(property, value);return list != null ? list.get(0) : null;}@Overridepublic List<T> findListByProperty(String property, Object value) {return findListByProperty(property, value, false);}@Overridepublic List<T> findListByProperty(String property, Object value, boolean anywhere) {CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();CriteriaQuery<T> query = criteriaBuilder.createQuery(getPersistentClass());Root<T> root = query.from(getPersistentClass());Predicate predicate;if (anywhere)predicate = criteriaBuilder.like(root.get(property), "%" + value.toString() + "%");elsepredicate = criteriaBuilder.equal(root.get(property), value);query.where(predicate);return em.createQuery(query).getResultList();}@Overridepublic List<T> findAll() {return dao.findAll();}@Overridepublic Pagination findAllPage(int pageNo, int pageSize, Sort.Order... orders) {Sort sort = orders != null && orders.length > 0 ? new Sort(orders) : null;Pageable pageable = new PageRequest(pageNo - 1, pageSize, sort);Page<T> page = dao.findAll(pageable);Pagination pagination = new Pagination(pageNo, pageSize, (int) page.getTotalElements());pagination.setList(page.getContent());return pagination;}@Overridepublic List<T> findList(T entity, Sort.Order... orders) {Example<T> example = Example.of(entity);if (orders != null && orders.length > 0)return dao.findAll(example, new Sort(orders));elsereturn dao.findAll(example);}@Override@SuppressWarnings("unchecked")public List<T> findList(T entity, int pageNo, int pageSize, Sort.Order... orders) {Pagination pagination = findListPage(entity, pageNo, pageSize, orders);if (pagination != null) {return (List<T>)pagination.getList();}return new ArrayList<>();}@Overridepublic Pagination findListPage(T entity, int pageNo, int pageSize, Sort.Order... orders) {Example<T> example = Example.of(entity);Sort sort = orders != null && orders.length > 0 ? new Sort(orders) : null;Pageable pageable = new PageRequest(pageNo - 1, pageSize, sort);Page<T> page = dao.findAll(example, pageable);Pagination pagination = new Pagination(pageNo, pageSize, (int) page.getTotalElements());pagination.setList(page.getContent());return pagination;}@Overridepublic T findLast() {return dao.findTopByOrderByIdDesc();}@Overridepublic T findFirst(T entity, Sort.Order... orders) {List<T> list = findList(entity, 1, 1, orders);if (!list.isEmpty()) {return list.get(0);}return null;}@Overridepublic long findAllCount() {return dao.count();}@Overridepublic long findCount(T entity) {Example<T> example = Example.of(entity);return dao.count(example);}@SuppressWarnings("rawtypes")protected Pagination find(Finder finder, int pageNo, int pageSize) {int totalCount = countQueryResult(finder);Pagination p = new Pagination(pageNo, pageSize, totalCount);if (totalCount < 1) {p.setList(new ArrayList());return p;}Query query = em.createQuery(finder.getOrigHql()).unwrap(Query.class);finder.setParamsToQuery(query);query.setFirstResult(p.getFirstResult());query.setMaxResults(p.getPageSize());List list = query.list();p.setList(list);return p;}/*** 通过count查询获得本次查询所能获得的对象总数.** @param finder* @return*/protected int countQueryResult(Finder finder) {Query query = em.createQuery(finder.getRowCountHql()).unwrap(Query.class);finder.setParamsToQuery(query);return ((Number) query.iterate().next()).intValue();}/*************************************************************************/private Class<T> persistentClass;@SuppressWarnings("unchecked")public BaseServiceImpl() {ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();this.persistentClass = (Class<T>) parameterizedType.getActualTypeArguments()[0];}private BaseJpaRepository<T, L> dao;public void setDao(BaseJpaRepository<T, L> dao) {this.dao = dao;}protected BaseJpaRepository<T, L> getDao() {return this.dao;}private Class<T> getPersistentClass() {return persistentClass;}public void setPersistentClass(Class<T> persistentClass) {this.persistentClass = persistentClass;}
}

BaseServiceImpl

package com.yjy.test.util.hibernate;/*** 分页接口*/
public interface Paginable {/*** 总记录数* * @return*/int getTotalCount();/*** 总页数* * @return*/int getTotalPage();/*** 每页记录数* * @return*/int getPageSize();/*** 当前页号* * @return*/int getPageNo();/*** 是否第一页* * @return*/boolean isFirstPage();/*** 是否最后一页* * @return*/boolean isLastPage();/*** 返回下页的页号*/int getNextPage();/*** 返回上页的页号*/int getPrePage();
}

Paginable

package com.yjy.test.util.hibernate;import java.util.List;/*** 列表分页。包含list属性。*/
@SuppressWarnings("serial")
public class Pagination extends SimplePage implements java.io.Serializable, Paginable {public Pagination() { }/*** 构造器* * @param pageNo*            页码* @param pageSize*            每页几条数据* @param totalCount*            总共几条数据*/public Pagination(int pageNo, int pageSize, int totalCount) {super(pageNo, pageSize, totalCount);}/*** 构造器* * @param pageNo*            页码* @param pageSize*            每页几条数据* @param totalCount*            总共几条数据* @param list*            分页内容*/public Pagination(int pageNo, int pageSize, int totalCount, List<?> list) {super(pageNo, pageSize, totalCount);this.list = list;}/*** 第一条数据位置** @return*/public int getFirstResult() {return (pageNo - 1) * pageSize;}/*** 当前页的数据*/private List<?> list;/*** 获得分页内容* * @return*/public List<?> getList() {return list;}/*** 设置分页内容* * @param list*/@SuppressWarnings("rawtypes")public void setList(List list) {this.list = list;}
}

Pagination

package com.yjy.test.util.hibernate;/*** 简单分页类*/
public class SimplePage implements Paginable {public static final int DEF_COUNT = 20;/*** 检查页码 checkPageNo* * @param pageNo* @return if pageNo==null or pageNo<1 then return 1 else return pageNo*/public static int cpn(Integer pageNo) {return (pageNo == null || pageNo < 1) ? 1 : pageNo;}/*** 检查每页条数* @author yjy* Created on 2017年12月5日 下午2:39:23* @param pageSize 条数* @return 矫正值*/public static int cps(Integer pageSize) {return (pageSize == null || pageSize < 1) ? DEF_COUNT : pageSize;}/*** 根据页号和条数计算起始下标* @author yjy* Created on 2017年12月6日 上午9:36:17* @param pageNo 页号* @param pageSize 条数* @return 起始下标 return (pageNo - 1) * pageSize*/public static int getStart(Integer pageNo, Integer pageSize) {return (cpn(pageNo) - 1) * cps(pageSize);}public SimplePage() {}/*** 构造器* * @param pageNo*            页码* @param pageSize*            每页几条数据* @param totalCount*            总共几条数据*/public SimplePage(int pageNo, int pageSize, int totalCount) {setTotalCount(totalCount);setPageSize(pageSize);setPageNo(pageNo);adjustPageNo();}/*** 调整页码,使不超过最大页数*/public void adjustPageNo() {if (pageNo == 1) {return;}int tp = getTotalPage();if (pageNo > tp) {pageNo = tp;}}/*** 获得页码*/public int getPageNo() {return pageNo;}/*** 每页几条数据*/public int getPageSize() {return pageSize;}/*** 总共几条数据*/public int getTotalCount() {return totalCount;}/*** 总共几页*/public int getTotalPage() {int totalPage = totalCount / pageSize;if (totalPage == 0 || totalCount % pageSize != 0) {totalPage++;}return totalPage;}/*** 是否第一页*/public boolean isFirstPage() {return pageNo <= 1;}/*** 是否最后一页*/public boolean isLastPage() {return pageNo >= getTotalPage();}/*** 下一页页码*/public int getNextPage() {if (isLastPage()) {return pageNo;} else {return pageNo + 1;}}/*** 上一页页码*/public int getPrePage() {if (isFirstPage()) {return pageNo;} else {return pageNo - 1;}}protected int totalCount = 0;protected int pageSize = 20;protected int pageNo = 1;/*** if totalCount<0 then totalCount=0* * @param totalCount*/public void setTotalCount(int totalCount) {if (totalCount < 0) {this.totalCount = 0;} else {this.totalCount = totalCount;}}/*** if pageSize< 1 then pageSize=DEF_COUNT* * @param pageSize*/public void setPageSize(int pageSize) {if (pageSize < 1) {this.pageSize = DEF_COUNT;} else {this.pageSize = pageSize;}}/*** if pageNo < 1 then pageNo=1* * @param pageNo*/public void setPageNo(int pageNo) {if (pageNo < 1) {this.pageNo = 1;} else {this.pageNo = pageNo;}}
}

SimplePage

    3: 使用 mvn package 打包项目时, 需要配置主类, 否则如果项目中存在多个类有main函数时, 打包会报错, 配置如下:

    

    4: 有一个比较实用的点, 就是可以通过@Value(property)注解将配置绑定至静态变量中, 下面是Redis静态配置类的例子:

package com.yjy.test.game.redis;import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;import javax.validation.constraints.NotNull;@Component
@Validated
public class RedisConfig {@NotNullpublic static String addr; //Redis服务器IP
@NotNullpublic static int port; //Redis的端口号public static String auth; //访问密码
@NotNullpublic static int maxActive = 10; // 可用连接实例的最大数目,默认值为8;如果赋值为-1,则表示不限制;// 如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
    @NotNullpublic static int maxIdle = 200; //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
@NotNullpublic static int timeOut = 2000; //连接的超时时间
@NotNullpublic static int maxWait = 10000; //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
@NotNullpublic static boolean testOnBorrow = true; //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
@NotNullpublic static boolean testOnReturn = true; //在return一个jedis实例时,是否提前进行validate操作.
@Value("${redis.addr}")public void setAddr(String addr) {this.addr = addr;}@Value("${redis.port}")public void setPort(int port) {this.port = port;}@Value("${redis.auth}")public void setAuth(String auth) {this.auth = auth;}@Value("${redis.maxActive}")public void setMaxActive(int maxActive) {this.maxActive = maxActive;}@Value("${redis.maxIdle}")public void setMaxIdle(int maxIdle) {this.maxIdle = maxIdle;}@Value("${redis.timeOut}")public void setTimeOut(int timeOut) {this.timeOut = timeOut;}@Value("${redis.maxWait}")public void setMaxWait(int maxWait) {this.maxWait = maxWait;}@Value("${redis.testOnBorrow}")public void setTestOnBorrow(boolean testOnBorrow) {this.testOnBorrow = testOnBorrow;}@Value("${redis.testOnReturn}")public void setTestOnReturn(boolean testOnReturn) {this.testOnReturn = testOnReturn;}public static void printAllConfig() {System.out.println("RedisConfig{" +"addr='" + addr + '\'' +", port=" + port +", auth='" + auth + '\'' +", maxActive=" + maxActive +", maxIdle=" + maxIdle +", timeOut=" + timeOut +", maxWait=" + maxWait +", testOnBorrow=" + testOnBorrow +", testOnReturn=" + testOnReturn +'}');}}

RedisConfig.java

大概就是这么个样子!!! 嗯

    

    

    

    

转载于:https://www.cnblogs.com/imyjy/p/8981345.html

SpringBoot webmvc项目导出war包并在外部tomcat运行产生的诸多问题以及解决方案相关推荐

  1. SpringBoot项目打成war包部署到外部Tomact运行

    需求:使用SpringBoot自带的Tomact在线上环境部署特别不方便,尤其是只更改几个文件就得全部打包部署,所以需要把SpringBoot打成war包部署到Tomact 1.在pom.xml中 由 ...

  2. 浅谈:Spring Boot原理分析,切换内置web服务器,SpringBoot监听项目(使用springboot-admin),将springboot的项目打成war包

    浅谈:Spring Boot原理分析(更多细节解释在代码注释中) 通过@EnableAutoConfiguration注解加载Springboot内置的自动初始化类(加载什么类是配置在spring.f ...

  3. springboot项目打war包发布到外置tomcat

    第一步:修改pom.xml 1. <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> ...

  4. idea导出war包并部署到tomcat

    文章目录 一.生成并导出war包 一.生成并导出war包 快捷键 ctrl+alt+shift+s打开 project structure 项目结构,点击artifacts,新建一个空的war包 点击 ...

  5. idea 导出war包,IDEA导出Web项目war包并放入Tomcat运行起来

    ### 目录 ### * * * 1.打开Web项目的项目结构 * 2.找到构件然后添加一个新的构件 * 3.添加完成后如图所示,留意下输出目录 * 4.之后关闭项目结构选择构建-编译Artifact ...

  6. 将JavaWeb项目打出war包并部署到tomcat

    war包:一般是一个web应用,例如网站:jar包:常用的java类 下面说一下打war包的方式: 一,项目打包 两种方式,一种使用eclipse自带的打包方式,另一种使用的Maven的. 第一种:e ...

  7. 【idea】【springboot】【jar】导出jar运行后报错java.lang.ClassNotFoundException 及springboot在idea导出jar包的正确方法

    文章目录 一.问题描述 二.问题分析 三.springboot在idea中导出jar包的正确方法 1.删除原有MANIFEST.MF 2.工程设置 3.导出jar包 总结 一.问题描述 使用idea将 ...

  8. idea如何将web项目打成war包maven和非maven

    前言: 如果要到服务器部署项目,可能需要将项目打成war包,最后放到tomcat的webapps下,这篇文章就讲解下如何将web项目打成war包. 正文: 将web项目打成war包有两种方式: 1.第 ...

  9. Linux中把文件夹打成war包,SpringBoot中maven项目打成war包部署在liunx服务器上的方法...

    说明:Spring Boot由于内嵌了如Tomcat,Jetty和Undertow这样的容器,也就是说可以直接跑起来,用不着再像Spring项目还需要外置的Tomcat等容器来进行部署工作了,通过启动 ...

最新文章

  1. (转)SplitContainer 控件(Windows 窗体)
  2. 阿里达摩院再造AI抗疫技术:20秒判读CT影像,识别准确率达96%,河南率先启用...
  3. 揭秘:蚂蚁金服bPaaS究竟是什么?
  4. 机器人 铑元素_中国青年化学家元素周期表专辑 | 胡淑贤:我为镨代言
  5. 程序员需要谨记的九大安全编码规则
  6. 软考信息安全工程师考试历年真题汇总及试题分布统计
  7. java jdk1.8 jvm_JDK1.8 JVM调优之初识JVM(一)
  8. python 装饰器相关 从后往前看
  9. PHP 正在迅速死去
  10. Windows登录密码轻松破解
  11. 一个表可以建几个索引_一个人失业在家,可以做哪些挣钱的小生意?推荐几个供参考...
  12. VPS搭建HTTP代理
  13. 驭电之道-用示波器测量二极管伏安特性曲线 模电实验 示波器 波形
  14. 项目范围管理(重点)-真题答案与解析
  15. 重磅宣布|强强联合,腾讯云携手Veeam提供云上数据存储服务
  16. Java一个简单的Employee类
  17. 移植MT7620A+MT7610E驱动到Openwrt trunk(Linux Kernel 3.14.18)(续:MT7620A)
  18. Revit二次开发_类别对应的BuiltInCategory枚举
  19. 课设复习之信息论固定算术编码与译码
  20. 交叉熵损失函数的计算公式

热门文章

  1. velocity模板 If / ElseIf / Else语法
  2. 【java开发系列】—— spring简单入门示例
  3. Coursera课程Python for everyone:Quiz: Many-to-Many Relationships and Python
  4. ASP.NET MVC Model绑定(二)
  5. tp3.2.3运用phpexcel将excel文件导入mysql数据库
  6. 腾讯,百度,网易游戏,华为笔面经验
  7. swift 注意事项 (十六) —— 可选链
  8. 【转】OpenGL反走样
  9. simulink中选择开关模块的使用
  10. indows 平台下 Go 语言的安装和环境变量设置