SpringBoot项目开发实战销售管理系统——项目框架搭建!
项目框架搭建
在完成项目的分析和数据库设计后,一般由架构师完成项目框架的搭建,包括项目依赖的添加、项目的配置和项目日志的配置,完成后再开始业务代码的编写。
技术栈的搭建
新建一个Spring Boot项目,选择的Spring Boot版本为2.3.10.RELEASE,使用Maven构建依赖,项目名称为sell-manager,设置当前项目的Maven坐标,其中groupId为com.onyx,artifactId为sell-manager。
(1)pom.xml的主要内容如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.10.RELEASE</version>
<relativePath/>
</parent>
<name>sell-manager</name>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-
8</project.reporting.outputEncoding>
<java.version>11</java.version>
</properties>
(2)在项目中添加依赖,代码如下:
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot 测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- Spring Boot JDBC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- Spring Boot 日志-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!--html 解析引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--MySQL驱动 -->
<dependency> <groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!--fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.55</version>
</dependency>
<!--Log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
<scope>compile</scope>
</dependency>
<!--guava-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0.1-jre</version>
</dependency>
<dependency>
<groupId>com.belerweb</groupId> <artifactId>pinyin4j</artifactId>
<version>2.5.1</version>
</dependency>
<!-- common-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10</version>
</dependency>
<!--commons-fileupload-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!-- 随机生成数据 -->
<dependency>
<groupId>com.github.jsonzou</groupId>
<artifactId>jmockdata</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
</dependencies>
(3)添加完依赖后,在application.properties中添加项目的相关配置信息,代码如下:
#端口号
server.port=8085#加载日志配置文件
logging.config=classpath:log4j2.xml
(4)配置数据库的连接信息,代码如下:
#druid
# 数据库访问配置
# 默认的主数据源
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/sell-manager?
useUnicode=
true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
#数据库的账号和密码
spring.datasource.username=root
spring.datasource.password=123456
#数据库连接池的配置
spring.datasource.removeAbandoned=true
spring.datasource.removeAbandonedTimeout=180
spring.datasource.logAbandoned=true
# 连接池的补充设置,将其应用到上面的所有数据源中
spring.datasource.initialSize=5 #数据库连接池初始化数量spring.datasource.minIdle=5 #数据库连接池最小数量
spring.datasource.maxActive=20 #数据库连接池最大数量# 配置获取连接等待超时时间
spring.datasource.maxWait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是ms(毫秒)
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 配置一个连接在池中最短生存的时间,单位是ms(毫秒)
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# 打开PSCache,并且指定每个连接中PSCache的大小
spring.datasource.poolPreparedStatements=truespring.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
(5)配置MyBatis,代码如下:
#当查询数据为空时字段返回null,不加查询数据为空时,字段将被隐藏
mybatis.configuration.call-setters-on-nulls=true
#开启驼峰命名并设置实体类的包位置
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.type-aliases-package=com.xisuo.sellmanager.entity
mybatis.mapper-locations=classpath:mapper/*.xml
(6)配置Freemaker模板引擎,代码如下:
#freemaker start
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
#文件的后缀为.ftl
spring.freemarker.suffix=.ftl
spring.freemarker.expose-request-attributes=true
spring.freemarker.expose-session-attributes=true
spring.freemarker.expose-spring-macro-helpers=true
#模板的位置
spring.freemarker.template-loader-path=classpath:/templates/
#编码方式全部是UTF-8
spring.freemarker.settings.default_encoding=UTF-8
spring.freemarker.settings.output_encoding=UTF-8
spring.freemarker.settings.url_escaping_charset=UTF-8#maxFileSize 单个数据大小#maxRequestSize 总数据大小
spring.servlet.multipart.maxFileSize = 5MB
spring.servlet.multipart.maxRequestSize=10MB
#freemaker end
(7)至此完成了项目最基本的技术栈的搭建工作。
注意:要设置整个项目的编码方式为UTF-8。
(8)完成项目各个分包的建立,为项目准备必要的开发文件,最终完成的目录结构如图9.8所示。
需要说明一下,在图9.8中,src的com.xisuo.sellmanager包下的目录含义如下:
aop:使用切面完成业务功能的实现。
config:项目的配置信息。
constant:项目中用到的常量。
controller:项目的所有控制器。
dao:项目的dao接口。
entity:数据库的实体类。
exception:异常处理。
interceptor:拦截器。
service:业务处理实现类。
utils:工具类。
在resources目录下的下一级目录的含义如下:
mapper:存放dao对应的xml目录。
pdf:存放pdf文件。
static:存放所有的静态文件,包括各种图片、js脚本文件和css文件。
templates:存放Freemaker模板。
application.properties:存放项目配置文件。
log4j2.xml:存放日志的配置文件。
(9)添加项目的所有静态文件到resources的static目录中,再新建日志配置文件log4j2.xml。当前保存用户的日志最长时间为90天,每天创建一个日志文件。log4j2.xml文件的内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="log.path" value="/web/xisuo/logs" />
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread]
%-5level%logger{20} - [%method,%line] - %msg%n" /> <!-- 控制台输出 -->
<appender name="console"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-info.log</file>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log
</fileNamePattern>
<!-- 日志最长的时间为90天 -->
<maxHistory>90</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-error.log</file>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log
</fileNamePattern>
<!-- 日志最长的时间为90天 -->
<maxHistory>90</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder> <filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 用户访问日志输出 -->
<appender name="sys-user"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-user.log</file>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log
</fileNamePattern>
<!-- 日志最长的时间为90天 -->
<maxHistory>90</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 显示形成的SQL、使用的参数和结果集 -->
<!--
<logger name="java.sql" level="debug" />
<logger name="org.springframework.jdbc" level="debug" /> -->
<logger name="com.xisuo" level="info" />
<root level="info">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
<!--系统用户操作日志-->
<logger name="sys-user" level="info">
<appender-ref ref="sys-user"/>
</logger>
</configuration>
(10)添加Spring Boot项目的启动类App,标记@EnableScheduling注解,从而开始定时任务,通过@MapperScan("com.xisuo.sellmanager.dao")注解扫描数据库接口的包,代码如下:
package com.xisuo.sellmanager;
//启动类
@EnableScheduling
@MapperScan("com.xisuo.sellmanager.dao")
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args); //必须有这个方法
}
}
项目的搭建
完成上面的基础框架搭建后,开始编写项目的通用代码,包括项目的配置、日志记录的处理、拦截器的编写和异常的处理等。
(1)配置日志的切面处理类WebLogAspect,记录所有的请求入参,代码如下:
package com.xisuo.sellmanager.aop;
//切面日志的处理
@Aspect
@Component
@Order(1)
public class WebLogAspect {
private static Logger logger =
LoggerFactory.getLogger(WebLogAspect.class);
//定义切入点,切入点为com.example.aop下的所有函数
@Pointcut("execution(public *com.xisuo.sellmanager.controller..*.*(..))")
public void webLog() {
}
//前置通知:在连接点之前执行的通知
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Exception {
// 接收请求,记录请求内容
ServletRequestAttributes attributes =
(ServletRequestAttributes)
RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//打印请求内容
logger.info("请求内容开始 请求地址:{} 请求方式:{}",
request.getRequest
URL().toString(), request.getMethod());
logger.info("请求类方法: {} 请求类方法参数: {} ",
joinPoint.getSignature(),
Arrays.toString(joinPoint.getArgs()));
}
@After("webLog()")
public void doAfter(JoinPoint joinPoint) throws Exception {
}
@AfterReturning(returning = "obj", pointcut = "webLog()")
public void doAfterReturning(Object obj) throws Throwable {
}
}
(2)配置项目的数据库连接池类
DruidDataSourceConfiguration,将application. properties中数据库的连接配置成自定义的连接Bean。配置代码如下:
package com.xisuo.sellmanager.config;
//数据库的配置
@Configuration
public class DruidDataSourceConfiguration {
private Logger logger = LoggerFactory.getLogger(DruidDataSource
Configuration.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.driver-class-name}")
……//省略部分代码
@Bean //声明其为Bean实例
@Primary //在同样的DataSource中,首先使用被标注的
DataSource
public DataSource dataSource() {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(dbUrl);
datasource.setUsername(username);
datasource.setPassword(password);
……//省略部分代码
datasource.setConnectionProperties(connectionProperties);
return datasource;
}
//注册一个StatViewServlet
@Bean
public ServletRegistrationBean DruidStatViewServle2() {
ServletRegistrationBean servletRegistrationBean = new Servlet
RegistrationBean(new StatViewServlet(), "/druid/*");
//添加初始化参数initParams
/** 白名单,如果不配置或value为空,则允许所有的IP访问 */
//
servletRegistrationBean.addInitParameter("allow","127.0.0.1,192.0.0.1"
);
/** 黑名单,与白名单存在相同的IP时,优先于白名单 */
//
servletRegistrationBean.addInitParameter("deny","192.0.0.1");
/** 用户名 */
servletRegistrationBean.addInitParameter("loginUsername",
"admin");
/** 密码 */
servletRegistrationBean.addInitParameter("loginPassword",
"admin");
/** 禁用页面上的Reset All功能 */
servletRegistrationBean.addInitParameter("resetEnable","false");
return servletRegistrationBean;
}
//注册一个WebStatFilter
@Bean
public FilterRegistrationBean druidStatFilter2() {
FilterRegistrationBean filterRegistrationBean = new Filter
RegistrationBean(new WebStatFilter());
/** 过滤规则 */
filterRegistrationBean.addUrlPatterns("/*");
/** 忽略资源 */
filterRegistrationBean.addInitParameter("exclusions",
"*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid2/*");
return filterRegistrationBean;
}
}
(3)本项目有HTML渲染需要用到js、css和图片等静态文件。静态文件的访问不需要登录,而直接根据URL请求静态文件即可。配置静态文件过滤器类ResourceConfig的代码如下:
package com.xisuo.sellmanager.config;
//静态文件过滤器的配置
@Configuration
public class ResourceConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//设置静态文件的存放目录
registry.addInterceptor(new ResourceInterceptor()).excludePath
Patterns("/static/**");
}
@Override
//需要告知系统,这里处理的文件要被当成静态文件
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
//设置上传的文件不拦截
TaleUtils.getUplodFilePath()//registry.addResourceHandler("/upload/**").addResourceLocations
("file:"+ "/" +"upload/");
//第一个方法设置访问路径前缀,第二个方法设置资源路径
registry.addResourceHandler("/static/**").addResourceLocations
("classpath:/static/");
}
}
(4)因为本例是Web项目,所以每一个对服务器的请求都需要判断是否合法,判断当前请求的用户是否已经成功登录系统,如果未登录,则不是合法的请求。对一些特殊的URL请求,可以设置不需要登录即可访问,例如登录请求、静态资源请求和错误页请求都不需要拦截。
package com.xisuo.sellmanager.config;
//拦截器的配置
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
//这里不要直接使用new LoginInterceptor,否则拦截器中的service会为null
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/", "/login","/static/**",
"/error");
//为了开发时不用登录即可测试接口
//registry.addInterceptor(loginInterceptor).excludePathPatterns
("/**");
}
}
(5)设置项目接口统一返回结果的实体类Result:
package com.xisuo.sellmanager.config.result;
/**对输出结果的封装,只要get方法而不要set方法*/
public class Result<T> {
private int code;
private String msg;
private T data;
private Result(T data){
this.code=0;
this.msg="success";
this.data=data;
}
private Result(CodeMsg mg) {
if (mg==null){
return;
}
this.code=mg.getCode();
this.msg=mg.getMsg();
}
//成功
public static <T> Result<T> success(T data){
return new Result<T>(data);
}
//失败
public static <T> Result<T> fail(CodeMsg mg){
return new Result<T>(mg);
}
//其他忽略
}
(6)新建项目全局异常处理类ExceptionHandle,捕获项目中
HttpRequestMethodNot-SupportedException不支持的方法异常及Exception异常,这些异常分别处理会得到不同的返回值,代码如下:
package com.xisuo.sellmanager.exception;
//异常的处理
@ControllerAdvicepublic class ExceptionHandle {
private static Logger logger =
LoggerFactory.getLogger(ExceptionHandle.class);
//异常的处理
@ExceptionHandler({Exception.class})
@ResponseStatus(HttpStatus.OK)
public ModelAndView handleException(Exception e){
ModelAndView m = new ModelAndView();
logger.error("服务器发生了异常,原因是:{}",e.toString());
m.addObject("error", e.getCause());
e.printStackTrace();
m.setViewName("error/500");
return m;
}
//不支持的方法
@ExceptionHandler({HttpRequestMethodNotSupportedException.class})
@ResponseStatus(HttpStatus.OK)
public ModelAndView methodSupport(Exception e){
ModelAndView m = new ModelAndView();
logger.error("不正确的访问方法,原因是:{}",e.getCause());
m.addObject("error", "不正确的访问方法");
e.printStackTrace();
m.setViewName("error/404");
return m;
}
}
(7)新建项目的登录拦截器LoginInterceptor.java文件,判断当前用户是否已经登录。如果没有登录,则跳转到登录页面,如果已经登录,则从cache中获取用户的信息并将其保存在ThreadLocal中,以方便在开发时获取用户的信息。处理完请求后执行afterCompletion方法,并清空ThreadLocal中的信息,以防止内存泄漏。
package com.xisuo.sellmanager.interceptor;
//登录过滤器
@Componentpublic class LoginInterceptor implements HandlerInterceptor {
private static Logger logger =
LoggerFactory.getLogger(LoginInterceptor.class);
@Autowired
@Qualifier("userService")
private UserService userService;
//在业务处理器处理请求之前调用。在企业开发中还可以进行编码、安全控制和权限校验等
预处理
@Override
public boolean preHandle(HttpServletRequest request, HttpServlet
Response response, Object handler) throws Exception {
//使用Cookie作为是否登录的判断依据
String value = CookieUtil.getCookieValue(request,
Constant.COOKIE_NAME);
String id = DESUtil.decrypt(value);
if (StringUtils.isBlank(value) || StringUtils.isBlank(id)) {
response.sendRedirect("/");
return false;
}
Object o = CacheUtils.get(Constant.USER_CACHE_PREFIX + id);
User user = null;
if (o != null) {
user = (User) o;
} else {
user = (User) CacheUtils.get(Constant.USER_CACHE_PREFIX +
id, () -> {
logger.info("拦截器缓存中没有用户{}的信息,去数据库中进行查询",
id);
return userService.getUserDetail(Long.parseLong(id));
});
}
if (user == null) {
response.sendRedirect("/");
return false;
}
CacheUtils.put(Constant.USER_CACHE_PREFIX + (user.getId()),
user);
UserContext.setUser(user);
return true;
} //在业务处理器处理执行请求完成后返回并生成视图之前执行
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse
response, Object handler, ModelAndView modelAndView) throws Exception
{
}
//在DispatcherServlet完全处理请求后被调用
//返回处理(已经渲染了页面)
@Override
public void afterCompletion(HttpServletRequest request,
HttpServlet
Response response, Object handler, Exception ex) throws Exception {
UserContext.remove();
}
}
(8)新建资源拦截器ResourceInterceptor.java文件,对静态资源进行过滤,代码如下:
package com.xisuo.sellmanager.interceptor;
//自定义的静态资源拦截器
public class ResourceInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServlet
Response response, Object handler) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, Http
ServletResponse httpServletResponse, Object o, ModelAndView
modelAndView)
throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Object o, Exception e) throwsException {
}
}
(9)新建当前访问用户的存储容器UserContext,每次登录时把用户信息放在当前的ThreadLocal容器中,以方便开发时获取用户信息,代码如下:
package com.xisuo.sellmanager.interceptor;
//持有用户的线程
public class UserContext {
private static ThreadLocal<User> userHolder=new ThreadLocal<>();
public static void setUser(User user){
userHolder.set(user);
}
public static User getUser(){
return userHolder.get();
}
public static void remove(){
userHolder.remove();
}
}
(10)新建分页实体类Page,在请求列表时返回分页信息,代码如下:
package com.xisuo.sellmanager.utils;
//分页的工具类
public class Page<T> implements Serializable {
private static final long serialVersionUID = 1L;
private int pageNo; //当前页数
private int pageSize; //每页显示的记录数
private int totalCounts; //总记录数
private int totalPages; //总页数
private int pageNum; //索引页数 private List<T> data; //列表数据
/* pageNo表示当前页,totalCounts表示总记录数,data表示数据*/
public Page(int pageNo, int totalCounts, List<T> data) {
this(pageNo, Constant.PAGE_SIZE, totalCounts, data);
}
/** 默认是第一页,一页15个,totalCounts表示总记录数,data表示数据*/
public Page(int totalCounts, List<T> data) {
this(Constant.PAGE, Constant.PAGE_SIZE, totalCounts, data);
}
/** pageNo表示第几页,pageSize表示一页多少个,totalCounts表示总记录数
*/
public Page(int pageNo, int pageSize, int totalCounts, List<T>
data) {
this.pageNo = pageNo;
this.pageSize = pageSize;
this.totalCounts = totalCounts;
this.totalPages = (totalCounts % pageSize == 0) ? totalCounts
/
pageSize : totalCounts / pageSize + 1;
this.pageNum = (pageNo - 1) * pageSize;
this.data = data;
}
private Page() {
}
//省略Get和Set方法
}
分页处理方法
因为很多列表的接口都会涉及分页参数的设置,考虑到参数设置的共性,这里抽取了一个参数处理类的服务类ParamService来处理所有的分页参数,其部分代码如下:
package com.xisuo.sellmanager.service.impl;
//参数服务类@Service("paramService")
public class ParamService {
private static Logger logger =
LoggerFactory.getLogger(ParamService.class);
//判断并处理传递的页码参数
public Map<String, Object> handlePageData(Integer pageNo) {
Map<String, Object> map = new HashMap<>(4);
if (pageNo == null || pageNo < 0) {
map.put("pageNum", (Constant.PAGE - 1) *
Constant.PAGE_SIZE);
map.put("pageNo", Constant.PAGE);
} else {
map.put("pageNum", (pageNo - 1) * Constant.PAGE_SIZE);
map.put("pageNo", pageNo);
}
map.put("pageSize", Constant.PAGE_SIZE);
return map;
}
/** 非空判断,不为空则放入数据,拼接前后的%,pair前面是名字,后面是值 */
public Map<String, Object> handleKeyLike(Map<String, Object> map,
Pair<String, String>... pair) {
if (map == null) {
return map;
}
for (Pair<String, String> immutablePair : pair) {
String right = immutablePair.getRight();
if (StringUtils.isNotBlank(right)) {
map.put(immutablePair.getLeft(), "%" + right + "%");
}
}
return map;
}
/** Integer不为空的判断,为空就保存默认值,不为空就放入数据
* @param triples 前面是名字,中间是值,第3个是默认值*/
public Map<String, Object> handleInt(Map<String, Object> map,
Triple
<String, Integer, Integer>... triples) {
if (map == null) {
return map;
}
for (Triple<String, Integer, Integer> triple : triples) { Integer middle = triple.getMiddle();
if (middle != null) {
map.put(triple.getLeft(), middle);
} else {
map.put(triple.getLeft(), triple.getRight());
}
}
return map;
}
//省略其他方法
}
本例还有一些很重要的工具类:MD5加密工具类MD5Util、时间工具类DateUtil等。这些工具类的代码就不一一列出,请读者下载后自行查看。
至此就完成了整个项目的搭建工作,解决了通用部分的代码编写,后续需要完成业务代码的开发工作,实现所有的业务功能,最后进行调试。