目录
6.获取Spring上下文的工具:applicationContext
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