一本码簿

众里寻码千百度,那段却在github处。

0%

Springboot+Mybatis+Maven

本次项目采用Springboot+Mybatis方式,使用注解式配置,增加全局异常处理,实现前端和后台参数传递过程下划线和驼峰法的自动转换。MyBatis官方没有提供基于Gradle的MyBtis Generator插件,因此沿用Maven做Build工具。


配置

application.yml关键配置

MyBatis配置如下:

1
2
3
4
5
mybatis:
mapper-locations: "classpath:mapper/*.xml"
type-aliases-package: "com.zjchey.dataManage.entity"
configuration:
map-underscore-to-camel-case: true

map-underscore-to-camel-case: true在生产代码时将数据库中下划线命名自动转为驼峰法命名代码。

Jackson配置如下:

1
2
3
jackson:
property-naming-strategy: SNAKE_CASE
defaultPropertyInclusion: NON_EMPTY

property-naming-strategy: SNAKE_CASE用于前端以application/json方式提交的POST请求的流参数转换,实现前端和后台双向自动下划线和驼峰法命名,后端接受参数的对象需要用@RequestBody修饰。
defaultPropertyInclusion: NON_EMPTY用于@ResponseBody修饰的接口在将对象转为json返回参数时,如果对象属性为null,则在json中忽略该属性。

注解配置

  1. 使用@Configuration修饰配置的类。
  2. 使用@Bean修饰的方法相当于xml配置中的bean标签,对应方法名为xml配置中的id属性,也可在用@Bean(name = "heou.net")的形式指定id。
  3. Spring的三种装配方式分别是:基于@Component@Autowired的隐式装配、基于@Configuration的Java显示装配和基于xml配置的显式装配。
  4. 在xml配置中,可通过构造器注入、setter注入的方式装配Bean。
  5. 在运行函数的类的配置如下:
    1
    2
    3
    @SpringBootApplication(scanBasePackages = "com.*.*")
    @MapperScan("com.*.*.*")
    @EnableTransactionManagement
    @SpringBootApplication 包括@Configuration、@EnableAutoConfiguration和@ComponentScan三个注解。

排除tomcat使用undertow

Maven:

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>

Gradle:

1
2
3
4
5
6
7
8
9
configurations {
compile.exclude module: 'spring-boot-starter-tomcat'
}

dependencies {
compile('org.springframework.boot:spring-boot-starter-web'){
exclude module: 'spring-boot-starter-tomcat'
}
}

logback日志

1
2
3
4
5
6
7
logging:
file: projectname.log
path: .
pattern: "%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n"
level:
root: info
org.springframework.web: warn

可指定类的日志输出级别。

MyBatis

MyBatis分页

内存分页

使用RowBounds

1
loggerMapper.getLogsBySortASC(new RowBounds(0,10));

Mybatis拦截器

待实现

第三方组件

PageHelper

通用mapper

通过泛型实现所有的mapper的CRUD操作,减少代码量。待实现,目前有通用Mapper4

MyBatis Generator

POM配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<overwrite>true</overwrite>
</configuration>
<dependencies>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.5</version>
</dependency>
</dependencies>
</plugin>

generatorConfig配置

1
2
3
4
5
<context id="context" targetRuntime="MyBatis3">

<table tableName="user" domainObjectName="UserSample"
enableSelectByPrimaryKey="false" enableUpdateByPrimaryKey="false"
enableDeleteByPrimaryKey="false" delimitIdentifiers="true"/>

targetRuntime=”MyBatis3”生产的代码包括selectByExample,delimitIdentifiers=”true”确保表名加引号,即使使用关键字(例如user)也可以正常查询。

常用功能

全局异常处理

1
2
3
4
5
6
7
8
9
10
11
@ControllerAdvice
public class GlobalExceptionHandler {
private final Logger logger=LoggerFactory.getLogger(getClass());

@ResponseBody
@ExceptionHandler(value = Exception.class)
public Result handlerGlobalException(Exception ex){
logger.error(ex.getMessage());
return new Result(ex.getMessage(),ResultType.ERROR);
}
}

若业务代码中无异常处理,可捕获controller和service中的异常。

统一返回消息格式

1.定义错误代码与错误消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public enum ResultType {
SUCCESS(200,"接口返回正常"),
FAILURE(5000,"接口返回失败"),
PARAMS_ERROR(5100,"提交参数错误"),
PARAMS_ERROR_MISS(5101,"必填参数缺失"),
PARAMS_ERROR_INVALID(5102,"参数无效"),
PERMISSION_DENIED(6000,"权限拒绝"),
DENIED_NOT_ROLE(6100,"角色权限拒绝"),
DENIED_NOT_ADMIN(6101,"非管理员权限"),
DENIED_NOT_USER(6102,"用户权限拒绝"),
ERROR(500,"接口调用错误"),
CUSTOM(999,"定制消息");

private Integer code;
private String msg;

ResultType(Integer code, String msg){
this.code=code;
this.msg=msg;
}
......
}
  1. 定义返回格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Result<T> {
@JsonIgnore
private ResultType resultType;
/*错误码*/
private Integer code;
/*提示信息 */
private String msg;
/*数据内容*/
private T data;

public Result(T data) {
this.data = data;
this.setResultType(null);
}

public Result(T data, ResultType resultType) {
this.data = data;
this.setResultType(resultType);
}
......
private void setResultType(ResultType type) {
this.resultType=type==null? ResultType.SUCCESS:type;
this.code= this.resultType.getCode();
this.msg= this.resultType.getMsg();
}
}
  1. 定义BaseController。

工具类使用

Google Guava

apache-commons-collections

apache-commons-fileupload

高级用法

数据库读写分离

redis二级缓存

统一前后端地址

使用反向代理

处理枚举

前后端字段下划线和驼峰法自动切换

指定property-naming-strategy: SNAKE_CASE
可实现后台到前端时的lowwer_camel转under_score但是,前端到后台时,后台接受参数的对象前加@RequestBody后,以Content-Type: application/json方式发POST请求时可以实现under_score转lowwer_camel
以application/x-www-form-urlencoded发POST请求时可以实现和Get请求均不能实现。

1.通过get请求或者application/x-www-form-urlencoded提交的POST请求

此情况下,参数可通过httpserveletRequest.getParams()获取

定义argumentreslover,如下:

1
2
3
class UnderScore2CamelArgumentResolver implements HandlerMethodArgumentResolver{
....
}

2.通过application/json提交的POST请求

此情况下,参数可通过httpserveletRequest.getInputStream()获取参数json流。

参考本文的Jackson配置

问题

Generator的xml文件如何读取application.yml内的内容

未解

yml中的日志名称改为项目名称

未解

Invalid bound statement (not found)

异常的全称如下:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):

网上大多提到的是xml的mapper无法扫描到,要在启动类配置@MapperScan(“com.*“),但本项目一开始犯了各低级的错误,application.xml的datasource.url配置成了jdbc:postgres://***,应该是jdbc:postgresql://***