@TOC
一、项目背景
作为技术人员的你,你可能遇到频繁的小项目不断的在创建(包括生产或技术语言),基础功能代码相似度达到90%,系统的基础接口、流程、参数等几近相似。每次新建项目就算你在熟悉,你也得花很大部分的时间(从数据库层到服务层到应用层到基础配置,我相信你在这里起码要花差不多半天的时间),不过你还是不断的创建类似项目、不断的添加数据库操作层、不断的服务接口和实现层,最后还要为外部提供API接口,其实当你项目做多了你就知道你一直在干重复的工作,在吸食没有营养的垃圾实物。你把大量的时间浪费在基础项目框架搭建、基础代码的编写。
1、手动创建项目型问题
你花了很多的时间仅仅是在做如下的工作:
- 创建WEB系统后台框架
你需要新建符合自己的项目,添加Spring工具、数据库工具、JSon处理、Redis处理、日志处理等,每次需要根据自己的需求去添加重复的maven依赖;
- 数据库MyBatis接口实现及映射配置
我们在后台经常使用MyBtis或JPA去做数据访问层,你需要编写对应的接口,还需要编写接口对应的SQL语句和映射关系,你需要对你设计的所有的table逐个一字不差的编写以便能顺利调试通过DAO接口,甚至你要添加很多个通过任意字段的组合都可以查询的通用接口,甚是吃力、费劲还不一定准确。
- 创建系统的实体模型
要实现与数据库的数据面向对象交互,我们必须提供与表相对应的PO对象,也就是我们系统中必须用到的entity,不同的系统虽然对应的model不太一样,但也就是model的名称和字段不一样而已,不过相同的是有一个名字、有n个不同名称的字段!为什么不能从数据中将表转换为实体,这样不就大大减少了代码量?
- 创建面向业务的服务接口
DAO是面向数据库层的,但是业务一般是变化的,所以我们一般系统中我们要抽离一层service接口出来面向系统业务实现事务操作,所以为了一般情况下针对业务层我们要实现业务接口层、业务接口实现层的所有代码,业务层在通过DAO层来实现数据库的CURD操作,其实你会发现这层的业务基础的逻辑几乎与DAO层完全相似(仅仅是个别的面向系统业务的接口需要个性化增加)。
- 创建面向应用的控制层接口
为了能提供对外接口,在MVC模式中我们还必须要提供对外的Controller层,也就是我们所说的API层,我们需要将对应的业务暴露给外部或第三方平台,要求规范外部请求参数、请求方式、请求接口地址等,所以不得已我们还必须实现一层业务控制层代码,通过调用业务服务层代码实现系统的业务功能。
- 创建系统配置
所以的应用启动都必须通过启动配置进行启动,可以包括开发环境配置、生产环境配置、测试环境配置等,其实这一类的配置也几近是相同的,可以统一起来配置,个性化的配置才需要用户自己添加。
- 创建日志配置
日志是系统必不可少的组件,我们的系统必须要配置对应的日志信息,包括保存目录、存储方式、日志级别等。不过这一部分基本上我们可以约定,差异性的才需要用户去更新,所以这部分的工作也可以统筹起来,使用代码生成。
- 工具集成配置
项目开发过程中我们需要借助很多工具来保证系统的稳定运行,包括分布式日志、SQL性能监控、跨域访问、JSON转换、文本转换、日期转换、加解密、文件操作、HTTP调用等等等,不过你会发现没新建一个项目你都会迫不及待的将你封装的、感觉很好用的工具统统都打包进去,因为你知道这个工具是很常用也基本上用的到,所以你每次都会拷贝它,我就想问,你每次这么做是不是感觉好累,导出查找位置、拷贝粘贴、修改包名!(当然,最好的方法不是拷贝进去二十封装层自己的一个jar包库到系统中)。
2、项目复制型新建项目问题
如果你发现这个多东西都是可复制的,只需要作为模板,然后按照模板修改就可以新建成另一个项目,不过你会发现即使你拷贝成另外一个项目你也会面对如下问题:
- 删除太多不必要的东西
被复制的项目一般包含了大量的与该系统业务相关的代码,所以你拿过去之后你需要删除所有与业务相关的代码;
- 接口实现大量改动
因为业务不同导致数据库设计不同所带来的问题就是基本上所有重要的代码都要删除或重构,包括系统实体模型、数据mapper层、业务service层、service实现层、控制层。你会发现你基本上还不如重建一个新项目还来得干脆!
- 环境兼容性
开发环境中,不是你改一个名字就可以到处运行,因为很多时候你修改的并不彻底,改完之后一直到其他地方或环境发现是错误、红点,不熟悉的开发人员根本无法解决对应的红色问题。
既然以上两种方案有如此多的问题,既然代码工作重复性如此之大,为何你依然固执于重建重加重改?那倒不如将重复的工作集成到一个项目中,以后创建项目的时候只需要专注于写好自己的SQL脚本,然后通过web网页或swagger输入自己的项目信息一键生成自己的项目,一气呵成,何乐而不为?这也是本人的初衷,也算是为公司为各位网友节省大量的开发时间和人力成本。
二、项目成果
对技术人员来说,技术都不是问题,缺的就是想法,基本上没有实现不了的事,剩下的就是时间的问题了,经过2-3天的开发,基本上成型,实现了自动生成SpringBoot后台代码的初衷。
1、代码生成服务
我将实现了代码生成的服务代码成了安装包,如下所示:
启动后如下所示(确保运行机器安装JDK并且80端口未被占用且按安装了mysql):
启动后远程机器监听的80端口,我们直接通过浏览器访问对应机器ip即可:
http://192.168.8.18进入登录页面
通过用户名admin,密码:123456进入系统即可(注意session在30分钟内过期重新登录)
2、项目创建
1、设计数据库
正如我说的,有了框架生成服务我们只需要专注于自己的数据库设计即可,这里我的业务是在音视频这块的应用,我设计了2个表,数据库脚本如下所示:
-- ------------------------------------------------------
-- 创建并使用数据库
-- ------------------------------------------------------
set charset utf8;
create database if not exists mclz character set UTF8;
use mclz;
--
-- 客户端链接信息表
--
create table if not exists t_connection
(
clientId bigint(20) NOT NULL, /* 客户端标识 */
ip varchar(16) default NULL, /* srs访问的地址 */
vhost varchar(64) default NULL, /* 虚拟主机 */
app varchar(64) default NULL, /* 应用名称 */
tcUrl varchar(256) default NULL, /* 访问地址 */
pageUrl varchar(256) default NULL, /* 访问页面 */
reserver1 varchar(128) default NULL, /* 保留字段 */
reserver2 varchar(128) default NULL, /* 保留字段 */
primary key(clientId)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='client connection information';
--
-- 视频发布信息表
--
create table if not exists t_publish
(
clientId bigint(20) NOT NULL, /* 客户端标识 */
ip varchar(16) default NULL, /* srs访问的地址 */
vhost varchar(64) default NULL, /* 虚拟主机 */
app varchar(64) default NULL, /* 应用名称 */
tcUrl varchar(256) default NULL, /* 访问地址 */
stream varchar(64) default NULL, /* 流名称 */
param varchar(128) default NULL, /* 携带参数 */
reserver1 varchar(128) default NULL, /* 保留字段 */
reserver2 varchar(128) default NULL, /* 保留字段 */
primary key(clientId)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='client publish stream';
--
-- 视频播放信息表
--
create table if not exists t_play
(
clientId bigint(20) NOT NULL, /* 客户端标识 */
ip varchar(16) default NULL, /* srs访问的地址 */
vhost varchar(64) default NULL, /* 虚拟主机 */
app varchar(64) default NULL, /* 应用名称 */
stream varchar(64) default NULL, /* 流名称 */
param varchar(128) default NULL, /* 携带参数 */
reserver1 varchar(128) default NULL, /* 保留字段 */
reserver2 varchar(128) default NULL, /* 保留字段 */
primary key(clientId)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='client play stream';
我的业务中简单的就三个表,客户端连接表、视频发布表、视频播放表,设计完成我的业务之后我们就可以通过上传该脚本生成自己的web后台系统,该系统包括了所有操作这3个表的DAO层、mybatis的XML配置、service层、service实现层、controller层以及以下静态网页。
2、创建项目
通过上面的步骤我们登陆到框架生成系统中,如下所示
这里的项目创建界面比较简洁,我算是偷个懒,有空的时候在为大家优化一下界面。需要注意些的都已经注明:
- 使用流程:设计数据库脚本=>填写项目信息=>上传数据库脚本=>创建项目
- 后续开发中,用户只需要关注数据库设计即可一键生成,不需要浪费大量时间构建后台系统代码
- 系统生成的后台使用的技术框架: SpringBoot+MyBtis+MySql的三层MVC服务架构
- 系统提供了如系统配置、日志配置、数据库配置、拦截器配置、转换器配置、Druid配置等相关配置代码的生成
- 系统提供了如控制层、服务接口层、服务实现层、数据访问层、Mybatis映射XML脚本等基础服务代码的生成
- 数据库表不支持联合主键类型的处理
我的sql脚本中创建的数据库名称为"mclz",所以我填入的项目信息如下所示:
项目包名:com.easystudy #该项作为所有包的基础包名应用到项目中
应用名称:hello #项目名称也是应用名称对应项目Context名
应用端口:6666 #项目对应的服务端口,http访问需明确指定
数据库地址:127.0.0.1 #部署机器必须安装mysql用户sql执行转化
数据库端口:3306 #服务暂时仅支持mysql数据库操作
数据库名称:mclz #设计的SQL中创建并使用的数据库名称
数据库用户:root #运行脚本的mysql连接用户名
数据库密码:root #运行脚本的mysql连接密码
数据库脚本:通过选择sql脚本文件上传后返回的sql临时文件名
点击“提交并创建项目”按钮新建项目,成功后自动下载新建完成后的项目!
我们直接下载项目并导入到eclipse中即可,最后直接运行
根据我们创建的项目名为hello,项目监听端口6666,我们直接浏览器访问:
http://localhost:6666/hello/
可以看到后台框架系统已经生成,接口也已经生成提供(后面一起看看),你只需要实现你的UI界面开发即可!
数据库性能监控页面:
http://localhost:6666/hello/druid
3、项目结构
生成好后台项目之后,我们一起来看看生成的项目的目录结构,如下所示:
可以看到生成的可运行系统基本囊括了后台SpringBoot后台应用框架的所有的代码,包括:
- controller层代码实现
部分代码如下:
package com.easystudy.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.PathVariable;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import com.easystudy.error.ErrorCode;
import com.easystudy.error.ReturnValue;
import com.easystudy.error.IOException;
import com.easystudy.model.Connection;
import com.easystudy.service.ConnectionService;
/**
* @文件名称: ConnectionController.java
* @功能描述: 控制层对外接口
* @版权信息: www.easystudy.com
* @技术交流: 961179337(QQ群)
* @编写作者: lixx2048@163.com
* @联系方式: 941415509(QQ)
* @开发日期: 2020年10月19日
* @历史版本: V1.0
* @备注信息:
*/
@Slf4j
@RestController
@RequestMapping("/tconnection")
@Api(tags = "Connection管理接口文档", value = "提供Connection管理相关接口")
public class ConnectionController {
@Autowired
private ConnectionService connectionService;
@PostMapping("/add")
@ApiOperation(value="添加Connection信息", notes="添加Connection信息")
@ApiImplicitParams({ @ApiImplicitParam(paramType = "body", dataType = "Connection", name = "connection", value = "Connection信息", required = true) })
public ReturnValue<String> add(@RequestBody() Connection connection){
try {
connectionService.add(connection);
return new ReturnValue<String>();
} catch (IOException e) {
log.error("添加信息异常:{}", e.getMessage());
e.printStackTrace();
}
return new ReturnValue<String>(ErrorCode.ERROR_SERVER_ERROR, "添加信息异常!");
}
@DeleteMapping("/delete/{clientId}")
@ApiOperation(value="删除Connection信息", notes="通过主键删除Connection信息")
@ApiImplicitParams({ @ApiImplicitParam(paramType = "path", dataType = "Long", name = "clientId", value = "主键标识", required = true)})
public ReturnValue<String> delete(@PathVariable(name="clientId", required=true) Long clientId){
try {
Connection temp = new Connection();
temp.setClientId(clientId);
connectionService.delete(temp);
return new ReturnValue<String>();
} catch (IOException e) {
log.error("删除信息异常:{}", e.getMessage());
e.printStackTrace();
}
return new ReturnValue<String>(ErrorCode.ERROR_SERVER_ERROR, "删除信息异常!");
}
@PutMapping("/update")
@ApiOperation(value="更新Connection信息", notes="更新Connection信息")
@ApiImplicitParams({ @ApiImplicitParam(paramType = "body", dataType = "Connection", name = "connection", value = "Connection信息", required = true) })
public ReturnValue<String> update(@RequestBody Connection connection) {
try {
connectionService.update(connection);
return new ReturnValue<String>();
} catch (IOException e) {
log.error("更新信息异常:{}", e.getMessage());
e.printStackTrace();
}
return new ReturnValue<String>(ErrorCode.ERROR_SERVER_ERROR, "删除信息异常!");
}
@GetMapping("/findById/{clientId}")
@ApiOperation(value="通过主键查找Connection信息", notes="通过主键查找Connection信息")
@ApiImplicitParams({ @ApiImplicitParam(paramType = "path", dataType = "Long", name = "clientId", value = "主键标识", required = true)})
public ReturnValue<Connection> findById(@PathVariable(name="clientId", required=true) Long clientId){
try {
Connection connection = connectionService.findById(clientId);
if(null == connection) {
return new ReturnValue<Connection>(ErrorCode.ERROR_NOT_FOUND);
}
return new ReturnValue<Connection>(connection);
} catch (IOException e) {
log.error("查询信息异常:{}", e.getMessage());
e.printStackTrace();
}
return new ReturnValue<Connection>(ErrorCode.ERROR_SERVER_ERROR, "查询信息异常!");
}
@GetMapping("/findMaxByAttributes")
@ApiOperation(value="通过属性查找Connection总数", notes="通过属性查找Connection总数")
@ApiImplicitParams({
@ApiImplicitParam(paramType = "query", dataType = "String", name = "ip", value = "ip", required = false),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "vhost", value = "vhost", required = false),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "app", value = "app", required = false),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "tcUrl", value = "tcUrl", required = false),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "pageUrl", value = "pageUrl", required = false),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "reserver1", value = "reserver1", required = false),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "reserver2", value = "reserver2", required = false)
})
public ReturnValue<Long> findMaxByAttributes(
@RequestParam(name="ip",required=false) String ip,
@RequestParam(name="vhost",required=false) String vhost,
@RequestParam(name="app",required=false) String app,
@RequestParam(name="tcUrl",required=false) String tcUrl,
@RequestParam(name="pageUrl",required=false) String pageUrl,
@RequestParam(name="reserver1",required=false) String reserver1,
@RequestParam(name="reserver2",required=false) String reserver2
) {
try {
Long count = connectionService.findMaxByAttributes(ip,vhost,app,tcUrl,pageUrl,reserver1,reserver2);
return new ReturnValue<Long>(count);
} catch (IOException e) {
log.error("查询信息异常:{}", e.getMessage());
e.printStackTrace();
}
return new ReturnValue<Long>(ErrorCode.ERROR_SERVER_ERROR, "查询信息异常!");
}
@GetMapping("/findByAttributes")
@ApiOperation(value="查找Connection信息列表", notes="查找Connection信息列表")
@ApiImplicitParams({
@ApiImplicitParam(paramType = "query", dataType = "Long", name = "pageIndex", value = "页索引", required = true),
@ApiImplicitParam(paramType = "query", dataType = "Long", name = "pageSize", value = "页大小", required = true),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "orderProp", value = "排序字段", required = false),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "order", value = "排序方式(asc、desc)", required = false),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "ip", value = "ip", required = false),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "vhost", value = "vhost", required = false),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "app", value = "app", required = false),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "tcUrl", value = "tcUrl", required = false),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "pageUrl", value = "pageUrl", required = false),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "reserver1", value = "reserver1", required = false),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "reserver2", value = "reserver2", required = false)
})
public ReturnValue<List<Connection>> findByAttributes(
@RequestParam(name="pageIndex",required=true) Long pageIndex,
@RequestParam(name="pageSize",required=true) Long pageSize,
@RequestParam(name="orderProp",required=false) String orderProp,
@RequestParam(name="order",required=false) String order,
@RequestParam(name="ip",required=false) String ip,
@RequestParam(name="vhost",required=false) String vhost,
@RequestParam(name="app",required=false) String app,
@RequestParam(name="tcUrl",required=false) String tcUrl,
@RequestParam(name="pageUrl",required=false) String pageUrl,
@RequestParam(name="reserver1",required=false) String reserver1,
@RequestParam(name="reserver2",required=false) String reserver2
) {
try {
List<Connection> list = connectionService.findByAttributes(pageIndex,pageSize,orderProp,order,ip,vhost,app,tcUrl,pageUrl,reserver1,reserver2);
return new ReturnValue<List<Connection>>(list);
} catch (IOException e) {
log.error("通过属性查询信息异常:{}", e.getMessage());
e.printStackTrace();
}
return new ReturnValue<List<Connection>>(ErrorCode.ERROR_SERVER_ERROR, "通过属性查询信息异常!");
}
}
- service接口层代码
部分代码实例:
package com.easystudy.service;
import com.easystudy.model.Connection;
import com.easystudy.error.IOException;
import java.util.List;
/**
* @文件名称: ConnectionService.java
* @功能描述: 业务服务层接口
* @版权信息: www.easystudy.com
* @技术交流: 961179337(QQ群)
* @编写作者: lixx2048@163.com
* @联系方式: 941415509(QQ)
* @开发日期: 2020年10月19日
* @历史版本: V1.0
* @备注信息:
*/
public interface ConnectionService extends BaseService<Connection> {
Long findMaxByAttributes(String ip,String vhost,String app,String tcUrl,String pageUrl,String reserver1,String reserver2) throws IOException;
List<Connection> findByAttributes(Long pageIndex,Long pageSize,String orderProp,String order,String ip,String vhost,String app,String tcUrl,String pageUrl,String reserver1,String reserver2) throws IOException;
}
- service接口实现层
部分代码示例:
package com.easystudy.service.impl;
import com.easystudy.model.Connection;
import com.easystudy.error.IOException;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.easystudy.mapper.ConnectionMapper;
import com.easystudy.service.ConnectionService;
/**
* @文件名称: ConnectionServiceImpl.java
* @功能描述: 业务服务实现类
* @版权信息: www.easystudy.com
* @技术交流: 961179337(QQ群)
* @编写作者: lixx2048@163.com
* @联系方式: 941415509(QQ)
* @开发日期: 2020年10月19日
* @历史版本: V1.0
* @备注信息:
*/
@Service
public class ConnectionServiceImpl implements ConnectionService {
@Autowired
private ConnectionMapper mapper;
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, isolation = Isolation.REPEATABLE_READ)
public void add(Connection o) throws IOException {
mapper.insertSelective(o);
}
@Override
public void delete(Connection o) throws IOException {
mapper.deleteByPrimaryKey(o.getClientId());
}
@Override
public void update(Connection o) throws IOException {
mapper.updateByPrimaryKeySelective(o);
}
@Override
public Connection findById(Object id) throws IOException {
return mapper.selectByPrimaryKey((Long)id);
}
@Override
public List<Connection> findByAttributes(Long pageIndex,Long pageSize,String orderProp,String order,String ip,String vhost,String app,String tcUrl,String pageUrl,String reserver1,String reserver2) throws IOException {
return mapper.selectByAttributes(pageIndex,pageSize,orderProp,order,ip,vhost,app,tcUrl,pageUrl,reserver1,reserver2);
}
@Override
public Long findMaxByAttributes(String ip,String vhost,String app,String tcUrl,String pageUrl,String reserver1,String reserver2) throws IOException {
return mapper.selectMaxByAttributes(ip,vhost,app,tcUrl,pageUrl,reserver1,reserver2);
}
}
- DAO接口层
部分实现代码:
package com.easystudy.mapper;
import com.easystudy.model.Connection;
import java.util.List;
import org.apache.ibatis.annotations.Param;
/**
* @文件名称: ConnectionMapper.java
* @功能描述: Dao层数据操作接口
* @版权信息: www.easystudy.com
* @技术交流: 961179337(QQ群)
* @编写作者: lixx2048@163.com
* @联系方式: 941415509(QQ)
* @开发日期: 2020年10月19日
* @历史版本: V1.0
* @备注信息:
*/
public interface ConnectionMapper {
int deleteByPrimaryKey(Long clientId);
int insert(Connection connection);
int insertSelective(Connection connection);
Connection selectByPrimaryKey(Long clientId);
int updateByPrimaryKeySelective(Connection connection);
int updateByPrimaryKey(Connection connection);
Long selectMaxByAttributes(@Param("ip")String ip,@Param("vhost")String vhost,@Param("app")String app,@Param("tcUrl")String tcUrl,@Param("pageUrl")String pageUrl,@Param("reserver1")String reserver1,@Param("reserver2")String reserver2);
List<Connection> selectByAttributes(@Param("pageIndex")Long pageIndex,@Param("pageSize")Long pageSize,@Param("orderProp")String orderProp,@Param("order")String order,@Param("ip")String ip,@Param("vhost")String vhost,@Param("app")String app,@Param("tcUrl")String tcUrl,@Param("pageUrl")String pageUrl,@Param("reserver1")String reserver1,@Param("reserver2")String reserver2);
}
- mybatis脚本层
部分代码示例:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.easystudy.mapper.ConnectionMapper" >
<resultMap id="BaseResultMap" type="com.easystudy.model.Connection" >
<id column="clientId" property="clientId" jdbcType="BIGINT" />
<result column="ip" property="ip" jdbcType="VARCHAR" />
<result column="vhost" property="vhost" jdbcType="VARCHAR" />
<result column="app" property="app" jdbcType="VARCHAR" />
<result column="tcUrl" property="tcUrl" jdbcType="VARCHAR" />
<result column="pageUrl" property="pageUrl" jdbcType="VARCHAR" />
<result column="reserver1" property="reserver1" jdbcType="VARCHAR" />
<result column="reserver2" property="reserver2" jdbcType="VARCHAR" />
</resultMap>
<sql id="Base_Column_List" >
clientId,ip,vhost,app,tcUrl,pageUrl,reserver1,reserver2
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >
select <include refid="Base_Column_List" />from t_connection where clientId = #{clientId,jdbcType=BIGINT}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long" >
delete from t_connection where clientId = #{clientId,jdbcType=BIGINT}
</delete>
<select id="selectMaxByAttributes" resultType="long">
select count(clientId) from t_connection
<where>
<if test="ip != null and ip.length() > 0">
ip like CONCAT('%',#{ip},'%')
</if>
<if test="vhost != null and vhost.length() > 0">
and vhost like CONCAT('%',#{vhost},'%')
</if>
<if test="app != null and app.length() > 0">
and app like CONCAT('%',#{app},'%')
</if>
<if test="tcUrl != null and tcUrl.length() > 0">
and tcUrl like CONCAT('%',#{tcUrl},'%')
</if>
<if test="pageUrl != null and pageUrl.length() > 0">
and pageUrl like CONCAT('%',#{pageUrl},'%')
</if>
<if test="reserver1 != null and reserver1.length() > 0">
and reserver1 like CONCAT('%',#{reserver1},'%')
</if>
<if test="reserver2 != null and reserver2.length() > 0">
and reserver2 like CONCAT('%',#{reserver2},'%')
</if>
</where>
</select>
<select id="selectByAttributes" resultMap="BaseResultMap">
select <include refid="Base_Column_List" /> from t_connection
<where>
<if test="ip != null and ip.length() > 0">
ip like CONCAT('%',#{ip},'%')
</if>
<if test="vhost != null and vhost.length() > 0">
and vhost like CONCAT('%',#{vhost},'%')
</if>
<if test="app != null and app.length() > 0">
and app like CONCAT('%',#{app},'%')
</if>
<if test="tcUrl != null and tcUrl.length() > 0">
and tcUrl like CONCAT('%',#{tcUrl},'%')
</if>
<if test="pageUrl != null and pageUrl.length() > 0">
and pageUrl like CONCAT('%',#{pageUrl},'%')
</if>
<if test="reserver1 != null and reserver1.length() > 0">
and reserver1 like CONCAT('%',#{reserver1},'%')
</if>
<if test="reserver2 != null and reserver2.length() > 0">
and reserver2 like CONCAT('%',#{reserver2},'%')
</if>
</where>
<if test="orderProp != null and orderProp.length() > 0">
order by
<choose>
<when test="order != null and order != 'desc' and order != 'asc'">
${orderProp} asc
</when>
<when test="order == null">
${orderProp}
</when>
<otherwise>
${orderProp} ${order}
</otherwise>
</choose>
</if>
limit #{pageIndex}, #{pageSize}
</select>
<insert id="insert" parameterType="com.easystudy.model.Connection" >
insert into t_connection(clientId,ip,vhost,app,tcUrl,pageUrl,reserver1,reserver2) values(#{clientId,jdbcType=BIGINT},#{ip,jdbcType=VARCHAR},#{vhost,jdbcType=VARCHAR},#{app,jdbcType=VARCHAR},#{tcUrl,jdbcType=VARCHAR},#{pageUrl,jdbcType=VARCHAR},#{reserver1,jdbcType=VARCHAR},#{reserver2,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="com.easystudy.model.Connection" >
insert into t_connection
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="clientId != null" >
clientId,
</if>
<if test="ip != null" >
ip,
</if>
<if test="vhost != null" >
vhost,
</if>
<if test="app != null" >
app,
</if>
<if test="tcUrl != null" >
tcUrl,
</if>
<if test="pageUrl != null" >
pageUrl,
</if>
<if test="reserver1 != null" >
reserver1,
</if>
<if test="reserver2 != null" >
reserver2,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="clientId != null" >
#{clientId,jdbcType=BIGINT},
</if>
<if test="ip != null" >
#{ip,jdbcType=VARCHAR},
</if>
<if test="vhost != null" >
#{vhost,jdbcType=VARCHAR},
</if>
<if test="app != null" >
#{app,jdbcType=VARCHAR},
</if>
<if test="tcUrl != null" >
#{tcUrl,jdbcType=VARCHAR},
</if>
<if test="pageUrl != null" >
#{pageUrl,jdbcType=VARCHAR},
</if>
<if test="reserver1 != null" >
#{reserver1,jdbcType=VARCHAR},
</if>
<if test="reserver2 != null" >
#{reserver2,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.easystudy.model.Connection" >
update t_connection
<set>
<if test="clientId != null" >
clientId = #{clientId,jdbcType=BIGINT},
</if>
<if test="ip != null" >
ip = #{ip,jdbcType=VARCHAR},
</if>
<if test="vhost != null" >
vhost = #{vhost,jdbcType=VARCHAR},
</if>
<if test="app != null" >
app = #{app,jdbcType=VARCHAR},
</if>
<if test="tcUrl != null" >
tcUrl = #{tcUrl,jdbcType=VARCHAR},
</if>
<if test="pageUrl != null" >
pageUrl = #{pageUrl,jdbcType=VARCHAR},
</if>
<if test="reserver1 != null" >
reserver1 = #{reserver1,jdbcType=VARCHAR},
</if>
<if test="reserver2 != null" >
reserver2 = #{reserver2,jdbcType=VARCHAR},
</if>
</set>
where clientId = #{clientId,jdbcType=BIGINT}
</update>
<update id="updateByPrimaryKey" parameterType="com.easystudy.model.Connection" >
update t_connection
clientId = #{clientId,jdbcType=BIGINT},
ip = #{ip,jdbcType=VARCHAR},
vhost = #{vhost,jdbcType=VARCHAR},
app = #{app,jdbcType=VARCHAR},
tcUrl = #{tcUrl,jdbcType=VARCHAR},
pageUrl = #{pageUrl,jdbcType=VARCHAR},
reserver1 = #{reserver1,jdbcType=VARCHAR},
reserver2 = #{reserver2,jdbcType=VARCHAR}
where clientId = #{clientId,jdbcType=BIGINT}
</update>
</mapper>
- 系统model层
3个表生成对应3个实体类-持久化对象(PO)
部分代码示例:
package com.easystudy.model;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
/**
* @文件名称: Connection.java
* @功能描述: 系统实体类
* @版权信息: www.easystudy.com
* @技术交流: 961179337(QQ群)
* @编写作者: lixx2048@163.com
* @联系方式: 941415509(QQ)
* @开发日期: 2020年10月19日
* @历史版本: V1.0
* @备注信息:
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Connection {
private Long clientId;
private String ip;
private String vhost;
private String app;
private String tcUrl;
private String pageUrl;
private String reserver1;
private String reserver2;
}
- 系统配置
包括跨域访问配置、Swagger配置以及MVC配置类
部分示例代码:
package com.easystudy.conf;
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;
/**
* @文件名称: CORSConfig.java
* @功能描述: 跨域访问配置
* @版权信息: www.easystudy.com
* @技术交流: 961179337(QQ群)
* @编写作者: lixx2048@163.com
* @联系方式: 941415509(QQ)
* @开发日期: 2020年10月19日
* @历史版本: V1.0
* @备注信息:
*/
@Configuration
public class CORSConfig {
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
// 允许cookies跨域
config.setAllowCredentials(true);
// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
config.addAllowedOrigin("*");
// #允许访问的头信息,*表示全部
config.addAllowedHeader("*");
// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
config.setMaxAge(18000L);
// 允许提交请求的方法,*表示全部允许
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
swagger访问地址:
http://localhost:6666/hello/druid/datasource.html
swagger接口文档:
- 系统使用错误码
后台系统错误码VO值对象类,提供json与实体的转化,支持携带错误码和错误描述
部分示例代码:
package com.easystudy.error;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
/**
* @文件名称: ReturnValue.java
* @功能描述: 系统返回值dto定义
* @版权信息: www.easystudy.com
* @技术交流: 961179337(QQ群)
* @编写作者: lixx2048@163.com
* @联系方式: 941415509(QQ)
* @开发日期: 2020年10月19日
* @历史版本: V1.0
* @备注信息:
*/
@JsonInclude(Include.NON_NULL)
public class ReturnValue<T> {
private Integer error = 0; // 错误
private String description = ""; // 错误描述
private T value; // 返回值【当error为ERROR_NO_SUCCESS才有可能返回值-判断值是否为空】
// 成功不带返回值
public ReturnValue(){
this.error = ErrorCode.ERROR_SUCCESS.getError();
this.description = "成功";
}
// 成功带返回值
public ReturnValue(T value){
if(null == value){
this.error = ErrorCode.ERROR_NOT_FOUND.getError();
this.description = "没有找到你需要的资源";
} else {
this.error = ErrorCode.ERROR_SUCCESS.getError();
this.description = "成功";
this.value = value;
}
}
// 返回错误
public ReturnValue(ErrorCode error){
this.error = error.getError();
this.description = error.getDescription();
}
// 返回错误--对错误描述进行更改
public ReturnValue(ErrorCode error, String description){
this.error = error.getError();
this.description = description;
}
// 返回错误
public ReturnValue(Integer error){
this.error = error;
this.description = ErrorCode.getDescription(error);
}
public ReturnValue(Integer error, String description){
this.error = error;
this.description = description;
}
public Integer getError() {
return error;
}
public boolean success(){
return error == ErrorCode.ERROR_SUCCESS.getError();
}
public void setError(Integer error) {
this.error = error;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
- 系统配置
自动生成系统配置文件
系统配置文件如下所示:
server:
port: 6666
servlet:
context-path: /hello
#nio的web服务配置
undertow:
#为工作者创建的I/O线程数
io-threads: 20
#工作者线程数量
worker-threads: 50
#访问日志
accesslog:
enabled: false
spring:
application:
name: hello
#NOSQL
redis:
host: localhost
port: 6379
password:
timeout: 6000
pool:
max-active: 20 #连接池最大连接数(使用负值表示没有限制)
max-wait: -1
max-idle: 8
min-idle: 0
#数据源
datasource:
name: mclz
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/mclz?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
username: root
password: root
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: SELECT 'x'
validation-query-timeout: 6
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: false
max-pool-prepared-statement-per-connection-size: 20
filters: stat
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
logging:
config: classpath:logback.xml
mybatis:
mapper-locations: classpath:mapping/*.xml
type-aliases-package: com.easystudy.model
- 静态网页
示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>欢迎登录hello系统</title>
<link rel="stylesheet" type="text/css" href="../css/login.css"/>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
- 系统POM配置
<?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.easystudy</groupId>
<artifactId>hello</artifactId>
<version>1.0.1.1</version>
<!-- spring boot项目 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 项目属性:子模块不能引用父项目的properties变量 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
<lombok.version>1.16.20</lombok.version>
</properties>
<!-- 项目依赖管理声明,统一管理项目依赖的版本信息,继承项目无需声明版本 -->
<dependencyManagement>
<!-- 依赖管理 -->
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- hystrix仪表盘 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>${hystrix.dashboard}</version>
</dependency>
<!-- Spring-Mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- 阿里巴巴druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!-- 阿里巴巴json序列化反序列化 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.46</version>
</dependency>
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<!--
RESTFul接口文档:通过接口访问文档:http://localhost:8762/swagger-ui.html,8762为服务配置的监听端口,默认8080
feign Finchley.RELEASE 2.0.3 版本与feign版本冲突,使用feign必须要配置2.5.0以上版本
-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
<!-- feign:本身支持Hystrix的
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>-->
<!-- 远程调用:2.0.0.RELEASE版本会导致服务注册到nacos上 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<!-- reids作为缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!-- httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.1</version>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- RESTFul接口文档:通过接口访问文档:http://localhost:8762/swagger-ui.html,8762为服务配置的监听端口,默认8080 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<!-- 配置文件读取 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<!--Lombok:消除模板代码-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- logback日志包 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Spring-Mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!-- 阿里巴巴druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
</dependencies>
<!-- 编译插件 -->
<build>
<plugins>
<!--spring boot maven插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!-- 包含本地jar包 -->
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 系统日志配置
系统配置如下:
<configuration>
<!-- 每个logger都关联到logger上下文,默认上下文名称为“default”,用于区分不同应用程序的记录。一旦设置,不能修该 -->
<contextName>hello</contextName>
<!--配置常量,在后面的配置中使用 -->
<property name="PROJECT_NAME" value="hello" />
<!--配置常量,在后面的配置中使用 -->
<property name="COMPANY_NAME" value="hello" />
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径 -->
<property name="LOG_HOME" value="/home/${COMPANY_NAME}/logs/${PROJECT_NAME}" />
<!--定义日志输出格式:左对齐级别 -日期 -消息 换行-->
<property name="LOG_PATTERN" value="[%-5p] - %d{yyyy-MM-dd HH:mm:ss} - %msg%n" />
<!-- 定义日志输出字符集 -->
<property name="LOG_CHARSET" value="UTF-8" />
<!-- 调试日志:输出控制台 -->
<appender name="CONSOLE-LOG" class="ch.qos.logback.core.ConsoleAppender">
<!--定义输出格式-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>${LOG_CHARSET}</charset>
</encoder>
<!-- 比INFO小的日志级别不会被打印出来:打印所有级别 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
</appender>
<!-- 正常INFO级别日志:输出文件-->
<appender name="INFO-LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--定义输出文件名-->
<file>${LOG_HOME}/info/${PROJECT_NAME}.log</file>
<!--定义输出格式-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>${LOG_CHARSET}</charset>
</encoder>
<!-- 比该配置的小的日志级别不会被打印出来 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<!--定义日志滚动的策略-->
<!-- TimeBasedRollingPolicy和SizeBasedTriggeringPolicy冲突,使用SizeAndTimeBasedRollingPolicy -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--定义文件滚动时的文件名的格式:dys-warn_2019-01-10-%i.log-->
<fileNamePattern>${LOG_HOME}/info/${PROJECT_NAME}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<!-- 每个文件大小最大200M -->
<maxFileSize>200MB</maxFileSize>
<!-- 最大保存n天 -->
<maxHistory>7</maxHistory>
<!-- 日志总保存量为2G:该属性在 1.1.6版本后 才开始支持-->
<totalSizeCap>2GB</totalSizeCap>
<!-- 启动时清除无效历史数据 -->
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
</appender>
<!-- 警告日志:输出文件-->
<appender name="WARN-LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--定义输出文件名-->
<file>${LOG_HOME}/warn/${PROJECT_NAME}.log</file>
<!--定义输出格式-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>${LOG_CHARSET}</charset>
</encoder>
<!-- 比该配置的小的日志级别不会被打印出来 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<!--定义日志滚动的策略-->
<!-- TimeBasedRollingPolicy和SizeBasedTriggeringPolicy冲突,使用SizeAndTimeBasedRollingPolicy -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--定义文件滚动时的文件名的格式:dys-warn_2019-01-10-%i.log-->
<fileNamePattern>${LOG_HOME}/warn/${PROJECT_NAME}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<!-- 每个文件大小最大200M -->
<maxFileSize>200MB</maxFileSize>
<!-- 最大保存n天 -->
<maxHistory>7</maxHistory>
<!-- 日志总保存量为2G:该属性在 1.1.6版本后 才开始支持-->
<totalSizeCap>2GB</totalSizeCap>
<!-- 启动时清除无效历史数据 -->
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
</appender>
<!-- 错误日志:输出文件-->
<appender name="ERROR-LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--定义输出文件名-->
<file>${LOG_HOME}/error/${PROJECT_NAME}.log</file>
<!--定义输出格式-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>${LOG_CHARSET}</charset>
</encoder>
<!-- 比该配置的小的日志级别不会被打印出来 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<!--定义日志滚动的策略-->
<!-- TimeBasedRollingPolicy和SizeBasedTriggeringPolicy冲突,使用SizeAndTimeBasedRollingPolicy -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--定义文件滚动时的文件名的格式:dys-warn_2019-01-10.log-->
<fileNamePattern>${LOG_HOME}/error/${PROJECT_NAME}_%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<!-- 每个文件大小最大500M -->
<maxFileSize>500MB</maxFileSize>
<!-- 最大保存n天 -->
<maxHistory>15</maxHistory>
<!-- 日志总保存量为2G:该属性在 1.1.6版本后 才开始支持-->
<totalSizeCap>2GB</totalSizeCap>
</rollingPolicy>
</appender>
<!-- 根日志输出:root为默认日志输出INFO或以上级别(additivity=true时被继承,或name类无法找到时被继承-->
<root level="INFO">
<!-- 输出到控制台 -->
<appender-ref ref="CONSOLE-LOG" />
<!-- 输出到各个类型日志文件 -->
<appender-ref ref="INFO-LOG" />
<appender-ref ref="WARN-LOG" />
<appender-ref ref="ERROR-LOG" />
</root>
<!-- 调试日志:输出控制台 -->
<appender name="CONSOLE-LOG2" class="ch.qos.logback.core.ConsoleAppender">
<!--定义输出格式-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>${LOG_CHARSET}</charset>
</encoder>
<!-- 比DEBUG小的日志级别不会被打印出来:打印所有级别 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
</appender>
<!-- mybatis输出:不继承根配置 -->
<logger name="com.easystudy.mapper" level="DEBUG" additivity="false">
<!-- 输出到控制台 -->
<appender-ref ref="CONSOLE-LOG2" />
</logger>
</configuration>
以上就是完整的、最基础的项目的代码生成介绍,该项目主要通过如下方式实现:
- 约定的名称、路径等
系统生成代码通过约定的值进行的,包括日志存储位置、名称、默认依赖。
- 默认的代码风格样式
代码风格使用比较规范的样式进行生成
- 默认的模板
所有的代码是依赖模板生成的,有模板的拷贝替换、模板依葫芦画瓢,这里可能有作者代码的身影在里面,见谅!
二、合作使用
源码获取、合作、技术交流请获取如下联系方式:
QQ交流群:961179337
微信账号:lixiang6153
公众号:IT技术快餐
电子邮箱:lixx2048@163.com
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。