Commit 14ef305f authored by lihaipeng's avatar lihaipeng

增加mybatisPlus支持

parent 82be6264
......@@ -5,14 +5,10 @@
>
> 持续更新
## 依赖环境
* JDK 1.8+
* Spring Cloud Version: Hoxton.SR4
* Spring Boot Alibaba Version: 2.2.1.RELEASE
* Spring Boot Version: 2.2.7.RELEASE
## 架构图
![](./architecture.png)
## 依赖中间件
* Mysql 5.6
## 中间件版本
* Nacos 1.2.1
* Sentinel 1.7.2
* RocketMQ 4.5.1
......@@ -20,14 +16,16 @@
## 功能
* 服务注册与发现(Nacos Discovery)
* 统一配置管理(Nacos Config)
* 高可用防护(Sentinel)- 生环境使用待研究
* 高可用防护(Sentinel)- 生环境使用待研究
* 动态路由及失败重试(OpenFeign、Ribbon)
* 网关权限校验(Spring Cloud Gateway)
## 待办列表
* 支持mybatis-plus - 未完成
* 支持Redis - 未完成
* 支持RocketMQ - 未完成
* 统一记录进出日志 - 未完成
* 统一进出日志 - 未完成
* Dockerfile - 未完成
* 统一接口管理(Swagger-Yapi) - 未完成
* 统一接口管理(Swagger、Yapi) - 未完成
* 调用链路跟踪(OpenTracing) - 未完成
* 集群监控(Prometheus、Grafana) - 未完成
* 日志收集分析(ELK) - 未完成
......@@ -14,15 +14,14 @@
<version>${unififi-api.version}</version>
<dependencies>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<exclusions>
<exclusion>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hystrix</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
......
......@@ -2,10 +2,14 @@ package com.unififi.demo.model;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
public class User {
@NotNull
private String name;
private Integer age;
}
......@@ -24,7 +24,6 @@ public class Demo1Application {
return new RestTemplate();
}
@Bean
public RestTemplate restTemplate1() {
return new RestTemplate();
......
......@@ -4,9 +4,7 @@ import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Component
@Configuration
@RefreshScope
@Getter
......
......@@ -35,6 +35,36 @@
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1.tmp</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
......
package com.unififi.demo.config;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
@Configuration
@RefreshScope
@Getter
public class AppConfig {
@Value("${user.name}")
public String username;
}
package com.unififi.demo.config;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
public class CodeGenerator {
/**
* <p>
* 读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotEmpty(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("jobob");
gc.setOpen(false);
// gc.setSwagger2(true); 实体属性 Swagger2 注解
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://39.106.6.97:3306/unififi_spring_cloud_guide?useUnicode=true&useSSL=false&characterEncoding=utf8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("unififi");
dsc.setPassword("YQA6o9pw1r");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
pc.setParent("com.unififi");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
/*
cfg.setFileCreate(new IFileCreate() {
@Override
public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
// 判断自定义文件夹是否需要创建
checkDir("调用默认方法创建的目录,自定义目录用");
if (fileType == FileType.MAPPER) {
// 已经生成 mapper 文件判断存在,不想重新生成返回 false
return !new File(filePath).exists();
}
// 允许生成模板文件
return true;
}
});
*/
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
// 配置自定义输出模板
//指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
// templateConfig.setEntity("templates/entity2.java");
// templateConfig.setService();
// templateConfig.setController();
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
// 公共父类
strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
// 写于父类中的公共字段
strategy.setSuperEntityColumns("id");
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setControllerMappingHyphenStyle(true);
// strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
\ No newline at end of file
package com.unififi.demo.config;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
/**
* 统一异常处理
*/
@RestControllerAdvice
public class ControllerExceptionHandler {
@ExceptionHandler(Exception.class)
public Map handleException(Exception e) {
Map map = new HashMap();
map.put("code", 500);
map.put("msg", e.getMessage());
return map;
}
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public Map handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
Map map = new HashMap();
map.put("code", 501);
map.put("msg", e.getMessage());
return map;
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
Map map = new HashMap();
MethodArgumentNotValidException exception = (MethodArgumentNotValidException) e;
map.put("code", 502);
map.put("msg", exception.getBindingResult().getAllErrors().get(0).getDefaultMessage());
return map;
}
}
package com.unififi.demo.config;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class HttpMessageConverterConfig {
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter fastConverter = new UheFastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
SerializerFeature[] serializerFeatures = new SerializerFeature[]{
// Date的日期转换器
SerializerFeature.WriteDateUseDateFormat,
// 循环引用
SerializerFeature.DisableCircularReferenceDetect
};
fastJsonConfig.setSerializerFeatures(serializerFeatures);
fastJsonConfig.setCharset(Charset.forName("UTF-8"));
fastConverter.setFastJsonConfig(fastJsonConfig);
List<MediaType> fastjsonSupportedMediaTypes = new ArrayList<>();
fastjsonSupportedMediaTypes.add(MediaType.TEXT_PLAIN);
fastjsonSupportedMediaTypes.add(MediaType.APPLICATION_JSON);
fastConverter.setSupportedMediaTypes(fastjsonSupportedMediaTypes);
HttpMessageConverter<?> converter = fastConverter;
return new HttpMessageConverters(converter);
}
private static class UheFastJsonHttpMessageConverter extends FastJsonHttpMessageConverter {
private static final Logger logger = LoggerFactory.getLogger(UheFastJsonHttpMessageConverter.class);
@Override
public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException,
HttpMessageNotReadableException {
Object obj = super.read(type, contextClass, inputMessage);
if (logger.isInfoEnabled()) {
logger.info("U2C-REQ-[{}]:{}", type.getTypeName(), JSON.toJSONString(obj));
}
return obj;
}
@Override
public void write(Object t, Type type, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
if (type.getTypeName().endsWith("ListResp")) {
if (logger.isInfoEnabled()) {
logger.info("U2C-RESP-[{}]:{}", type.getTypeName(), "LIST_IGNORE");
}
} else {
if (logger.isInfoEnabled()) {
logger.info("U2C-RESP-[{}]:{}", type.getTypeName(), JSON.toJSONString(t));
}
}
super.write(t, type, contentType, outputMessage);
}
}
}
package com.unififi.demo.config;
import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.util.ArrayList;
import java.util.List;
@EnableTransactionManagement
@Configuration
@MapperScan(basePackages = {"com.unififi.*.mapper*"})
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
paginationInterceptor.setOverflow(false);
paginationInterceptor.setLimit(10);
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
List<ISqlParser> sqlParserList = new ArrayList<>();
// 攻击 SQL 阻断解析器、加入解析链
sqlParserList.add(new BlockAttackSqlParser());
paginationInterceptor.setSqlParserList(sqlParserList);
return paginationInterceptor;
}
}
\ No newline at end of file
......@@ -26,7 +26,7 @@ public class Demo2Controller {
return userService.add(user);
}
@GetMapping("/user/list")
@RequestMapping(value = "/user/list", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<User> list() throws InterruptedException {
Thread.sleep(5000L);
return userService.list();
......@@ -35,7 +35,7 @@ public class Demo2Controller {
@GetMapping("/user/get")
public User get(@RequestParam("name") String name) throws InterruptedException {
Thread.sleep(5000L);
System.out.println("user/get "+ name);
System.out.println("user/get " + name);
return userService.get(name);
}
}
package com.unififi.demo.entity;
import lombok.Data;
@Data
public class DemoUser {
private static final long serialVersionUID = 1L;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 邮箱
*/
private String email;
}
package com.unififi.demo.mapper;
import com.unififi.demo.entity.DemoUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface DemoUserMapper extends BaseMapper<DemoUser> {
}
package com.unififi.demo.service;
import com.unififi.demo.model.User;
import lombok.extern.java.Log;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Log
@Service
public class UserServiceImpl implements UserService {
private static final List<User> USERS = new ArrayList<>();
@Override
public String echo(String string) {
return "unififi-demo2-service echo: " + string;
}
@Override
public List<User> list() {
log.info("user list. size:" + USERS.size());
return USERS;
}
@Override
public User get(String name) {
return USERS.stream().filter(u -> name.equals(u.getName())).collect(Collectors.toList()).get(0);
}
@Override
public Boolean add(User user) {
log.info("user add. tostring:" + user.toString());
USERS.add(user);
return true;
}
}
package com.unififi.demo.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.unififi.demo.entity.DemoUser;
import com.unififi.demo.mapper.DemoUserMapper;
import com.unififi.demo.model.User;
import com.unififi.demo.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
public class UserServiceImpl implements UserService {
@Autowired
private DemoUserMapper demoUserMapper;
@Override
public String echo(String string) {
return "unififi-demo2-service echo: " + string;
}
@Override
public List<User> list() {
List<User> list = new ArrayList<>();
QueryWrapper<DemoUser> queryWrapper = new QueryWrapper<>();
List<DemoUser> demoUsers = demoUserMapper.selectList(queryWrapper);
log.info("user list. size:" + demoUsers.size());
for (DemoUser userEntity : demoUsers) {
User user = new User();
BeanUtils.copyProperties(userEntity, user);
list.add(user);
}
return list;
}
@Override
public User get(String name) {
// return USERS.stream().filter(u -> name.equals(u.getName())).collect(Collectors.toList()).get(0);
QueryWrapper<DemoUser> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", name);
DemoUser userEntity = demoUserMapper.selectOne(queryWrapper);
User user = new User();
BeanUtils.copyProperties(userEntity, user);
return user;
}
@Override
public Boolean add(User user) {
DemoUser userEntity = new DemoUser();
userEntity.setName(user.getName());
userEntity.setAge(user.getAge());
int insert = demoUserMapper.insert(userEntity);
log.info("user add. tostring:{} {}", user.toString(), insert);
return true;
}
}
......@@ -7,4 +7,38 @@ management:
include: '*'
spring:
application:
name: unififi-demo2-service
\ No newline at end of file
name: unififi-demo2-service
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://39.106.6.97:3306/unififi_spring_cloud_guide?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: unififi
password: YQA6o9pw1r
druid:
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: config,wall,stat
# 初始化数量
initialSize: 5
# 最小连接池数量
minIdle: 5
# 最大连接池数量
maxActive: 20
# 连接超时时间
maxWait: 60000
# 打开psCache, 对支持游标的数据库性能提升巨大
poolPreparedStatements: true
# 指定每个连接PsCache的大小
maxPoolPreparedStatementPerConnectionSize: 20
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 指定一个空闲连接最少空闲多久后可被清除,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 验证数据库连接的查询语句
validationQuery: select 1
# 当连接空闲时,是否执行连接测试
testWhileIdle: true
# 当从连接池借用连接时,是否测试该连接
testOnBorrow: false
# 在连接归还到连接池时是否测试该连接
testOnReturn: false
# 打开mergeSql,慢sql记录
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment