目錄
1.引入相關的pom依賴
2.編寫基本的類
3.全局異常定義與處理
4.校驗工具類編寫
5.JSON轉換工具開發
6.擷取Spring上下文的工具:applicationContext
7.Http請求前後的監聽工具
1.引入相關的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wx</groupId>
<artifactId>permission</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>permission</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--熱部署依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!--SpringBoot開啟AOP功能-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<!--guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.1-jre</version>
</dependency>
<!--mysql依賴-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
</dependency>
<!--連接配接池依賴-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.0</version>
</dependency>
<!--mybatis依賴-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<!--通用Mapper的依賴-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
<!--jackson-datatype-guava -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-guava</artifactId>
<version>2.10.1</version>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!--校驗相關類-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.0.Final</version>
</dependency>
<!--tools-->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.13</version>
</dependency>
<!--jackson-->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
包括整合MyBatis,通用Mapper,資料的傳回格式JsonData,編寫BaseDTO等等。
JsonData:
package com.wx.permission.infra.common;
import lombok.Getter;
import lombok.Setter;
/**
* User: Mr.Wang
* Date: 2019/12/14
*/
@Getter
@Setter
public class JsonData {
private Boolean ret;
private String msg;
private Object data;
public JsonData(Boolean ret) {
this.ret = ret;
}
public static JsonData success(String msg, Object data) {
JsonData jsonData = new JsonData(true);
jsonData.msg = msg;
jsonData.data = data;
return jsonData;
}
public static JsonData success(Object data) {
JsonData jsonData = new JsonData(true);
jsonData.data = data;
return jsonData;
}
public static JsonData success() {
return new JsonData(true);
}
public static JsonData fail(String msg) {
JsonData jsonData = new JsonData(true);
return jsonData;
}
}
2.編寫基本的類
package com.wx.permission.infra.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.checkerframework.checker.units.qual.A;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* User: Mr.Wang
* Date: 2019/12/14
*/
@Table(name = "sys_acl")
@Accessors(chain = true)
@Setter
@Getter
public class AclDTO {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ApiModelProperty("權限碼")
private String code;
private String name;
private Long aclModuleId;
@ApiModelProperty("請求的url,可以填正規表達式")
private String url;
@ApiModelProperty("類型。1 菜單 2按鈕 3其他")
private Short type;
@ApiModelProperty("該權限是否可以用 1可用,0不可用")
private Boolean status;
private String remark;
}
這裡需要注意的時已攻入了lombok的包,是以可以省略get set方法,建立對象的時候還可以進行鍊式調用,然後是主鍵的一個生成的政策,這個注解是必須要打上的不然項目啟動會報錯,
@GeneratedValue注解有兩個屬性,分别是strategy和generator:
generator屬性的值是一個字元串,預設為"",其聲明了主鍵生成器的名稱。
strategy屬性:提供四種值:

預設SpringBoot的@GeneratedValue 是不需要加參數的,但是如果資料庫控制主鍵自增(auto_increment), 不加參數就會報錯
3.全局異常定義與處理
這裡有三種種當時處理全局的異常, HandlerExceptionResolver,@Controlleradvice ,@ExceptionHandler
- @ExceptionHandler
注解隻能作用為對象的方法上,并且在運作時有效,value() 可以指定異常類。由該注解注釋的方法可以具有靈活的輸入參 數。異常參數可以包括一般的異常或特定的異常(即自定義異常),如果注解沒有指定異常類,會預設進行映射。
用法:
- HandlerExceptionResolver 接口
HandlerExceptionResolve 雖然能夠處理全局異常,但是 Spring 官方不推薦使用它。
用法:這裡他可以拿到請求參數的資訊,可以去做一些判斷
- @Controlleradvice 注解
用法:
package com.wx.permission.infra.exception;
/**
* User: Mr.Wang
* Date: 2019/12/14
*/
public class CommonException extends RuntimeException {
// private Long id;
public CommonException() {
super();
}
public CommonException(String message) {
super(message);
}
public CommonException(String message, Throwable cause) {
super(message, cause);
}
public CommonException(Throwable cause) {
super(cause);
}
protected CommonException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package com.wx.permission.infra.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import java.util.HashMap;
import java.util.Map;
/**
* User: Mr.Wang
* Date: 2019/12/14
*/
/**
* 全局自定義異常處理
*/
@ControllerAdvice
public class ControllerExceptionHandler {
//現在我要我自定義異常傳回的資訊是一個Map
@ExceptionHandler(CommonException.class)
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Map<String, Object> handUserNotExistException(CommonException ex) {
Map<String, Object> map = new HashMap<>();
// map.put("id", ex.getId());
map.put("message", ex.getMessage());
return map;
}
}
如果說不用@ControllerAdvice直接抛出異常,那麼傳回:
适用他的好處就是可以去封裝特定的傳回資訊:
4.校驗工具類編寫
校驗工具類主要是對validator的封裝,他提供了哪些預設的校驗,以及如何自定義校驗,如何分組校驗在文章SpringMVC--01(SpringMVC的資料校驗)裡面,隻是這裡呢不在使用@Valida來校驗,而是使用自己的封裝的類來校驗并傳回指定的異常。
package com.wx.permission.api.validator;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.wx.permission.infra.exception.CommonException;
import org.apache.commons.collections.MapUtils;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.*;
/**
* User: Mr.Wang
* Date: 2019/12/14
* <p>
* 這個類可以拿到按照自己喜歡的參數格式來封裝校驗結果
* 所有的校驗結果,BindingResult都可以拿到
*/
public class BeanValidator {
private static ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
/**
* 檢驗一個Bean
*
* @param t
* @param groups
* @param <T>
* @return
*/
public static <T> Map<String, String> validate(T t, Class... groups) {
Validator validator = validatorFactory.getValidator();
Set<ConstraintViolation<T>> validateResult = validator.validate(t, groups);
if (validateResult.isEmpty()) {
return Collections.emptyMap();
} else {
LinkedHashMap error = Maps.newLinkedHashMap();
Iterator iterator = validateResult.iterator();
while (iterator.hasNext()) {
ConstraintViolation constraintViolation = (ConstraintViolation) iterator.next();
error.put(constraintViolation.getPropertyPath().toString(), constraintViolation.getMessage());
}
return error;
}
}
/**
* 校驗集合 ???? 校驗邏輯
*
* @param collection
* @return
*/
public static Map<String, String> validateList(Collection<?> collection) {
//Preconditions和斷言的思想一緻
Preconditions.checkNotNull(collection);
Iterator<?> iterator = collection.iterator();
Map erros;
do {
//如果這個List的第一個元素沒有錯 第二個元素有錯能檢測到嗎?
if (!iterator.hasNext()) {
return Collections.emptyMap();
} else {
//new Class[0]表示有零個元素的Class數組,即空數組,
// 與傳入null結果是一樣的,
// 都表示取得無參構造方法。但是循環的時候他不會抛錯。
erros = validate(iterator.next(), new Class[0]);
}
} while (erros.isEmpty());
return erros;
}
/**
* 可以傳多個參數的校驗
*
* @param first
* @param objects
* @return
*/
public static Map<String, String> validatorObject(Object first, Object... objects) {
if (objects != null && objects.length >= 0) {
return validateList(Arrays.asList(first, objects));
} else {
return validate(first, new Class[0]);
}
}
/**
* 校驗不過抛出異常
* @param parms
* @throws CommonException
*/
public static void check(Object parms) throws CommonException {
Map<String, String> validatorRet = validatorObject(parms);
if (MapUtils.isNotEmpty(validatorRet)) {
throw new CommonException(validatorRet.toString());
}
}
}
new Class[0]就是傳入一個空數組,如果直接傳nul進去曆遍會報錯。
使用就非常簡單:
這是一個公共的校驗方法,如果對象需要校驗特俗的規則那麼可以如下:
public class AppInstanceValidator {
//appServiceInstance name
private static final String NAME_PATTERN = "[a-z]([-a-z0-9]*[a-z0-9])?";
private AppInstanceValidator() {
}
public static void checkName(String name) {
if (!Pattern.matches(NAME_PATTERN, name)) {
throw new CommonException("error.app.instance.name.notMatch");
}
}
}
如果這個特俗的規則在個對象的字段上用到,可以寫成注解,使用上面的通用對象校驗的類依然可以校驗。
5.JSON轉換工具開發
主要是對jaskon的一個封裝:
package com.wx.permission.infra.utils;
/**
* User: Mr.Wang
* Date: 2019/12/15
*/
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.ser.impl.SimpleFilterProvider;
import org.codehaus.jackson.type.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 封裝Jackson 把一個類轉換成json對象,把一個json轉換成類對象
*/
public class JsonMapper {
private static final Logger logger = LoggerFactory.getLogger(JsonMapper.class);
private static ObjectMapper objectMapper = new ObjectMapper();
static {
//初始化objectMapper的配置,處理空字段
objectMapper.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES);
objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
objectMapper.setFilters(new SimpleFilterProvider().setFailOnUnknownId(false));
objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_EMPTY);
}
/**
* 對象轉換為json
*
* @param src
* @param <T>
* @return
*/
public static <T> String object2String(T src) {
if (src == null) {
logger.warn("parse object is null");
return null;
}
try {
return src instanceof String ? (String) src : objectMapper.writeValueAsString(src);
} catch (Exception e) {
logger.warn("parse object to String exception,error:{}", e);
return null;
}
}
/**
* json轉換為對象
*
* @param src
* @param tTypeReference
* @param <T>
* @return
*/
public static <T> T string2Object(String src, TypeReference<T> tTypeReference) {
if (src == null || tTypeReference == null) {
return null;
}
try {
return (T) (tTypeReference.getType().equals(String.class) ? src : objectMapper.readValue(src, tTypeReference));
} catch (Exception e) {
logger.warn("parse String to object exception,String:{}, TypeReference<T>:{},error:{} ", src, tTypeReference, e);
return null;
}
}
}
6.擷取Spring上下文的工具:applicationContext
package com.wx.permission.infra.common;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
/**
* User: Mr.Wang
* Date: 2019/12/15
*/
@Component("applicationContextHelper")
public class ApplicationContextHelper implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
applicationContext = context;
}
/**
* 根據Class傳回容器中的Bean
*
* @param clazz
* @param <T>
* @return
*/
public static <T> T popBean(Class<T> clazz) {
if (applicationContext == null) {
return null;
}
return applicationContext.getBean(clazz);
}
/**
* 根據name和Class傳回Bean
*
* @param name
* @param clazz
* @param <T>
* @return
*/
public static <T> T popBean(String name, Class<T> clazz) {
if (applicationContext == null) {
return null;
}
return applicationContext.getBean(name, clazz);
}
// @Override
// public int getOrder() {
// return Ordered.HIGHEST_PRECEDENCE;
// }
}
7.Http請求前後的監聽工具
主要有什麼作用呢?可以用來輸出請求的參數資訊,敏感資訊需要過濾,可以用來記錄調用接口的時間
過濾器隻能獲得原始的http請求和響應,而無法獲得具體調用的哪個方法,要想獲得就要使用過濾器,需要注意的事自己處理了的異常在最後的afterCompletion拿不到。
package com.wx.permission.infra.common;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* User: Mr.Wang
* Date: 2019/12/15
*/
@Component
public class HttpInterceptor extends HandlerInterceptorAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
super.afterCompletion(request, response, handler, ex);
}
}
他每個方法的含義和使用在:https://blog.csdn.net/weixin_37650458/article/details/100637670