该文章主要教大家如何去除重复性的代码,减少代码的行数
Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,通过使用对应的注解,可以在编译源码的时候生成对应的方法。
org.projectlombok
lombok
@Getter可以自动生成get方法
@Setter可以自动生成set方法
@ToString可以重写toString方法,打印对象拥有的属性信息
如果不重写toString方法,实体类对象的toString方法只会输出对象内存地址信息,
一般我们会手动重写toString方法,把对象的属性信息打印出来,代码如下,使用@ToString注解,下面的代码就可以删掉了。
@Override
public String toString(){
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", age='" + age + '\'' +
'}';
}
@Data注解包含@Getter,@Setter,@ToString这3个注解的功能
我一般都用@Data注解
代码应用如下
@Data
public class User {
public User(){ }
public User(String username,String password,Integer age){
this.setUsername(username);
this.setPassword(password);
this.setAge(age);
System.out.println(this);
}
private String username;
private String password;
private Integer age;
public static void main(String[] args) {
new User("Dominick Li","123456",25);
}
}
@Slf4j可以去除log对象的声明
我们一般在需要打印日志的类里都要写下面代码
public class LogTest {
public static final Logger logger= LoggerFactory.getLogger(LogTest.class);
public static void main(String[] args) {
logger.info("打印info级别日志");
}
}
优化后的代码如下
@Slf4j
public class LogTest {
public static void main(String[] args) {
log.info("打印info级别日志");
}
}
如果项目不允许使用lombok插件,那我们可以通过使用commons.lang3包下的ToStringBuilder类实现重写toString方法
org.apache.commons
commons-lang3
3.7
通常我们会在基类定义一些通用属性,如记录的id,创建时间,修改时间
我们把重写toString的方法在基类中定义
public class BaseModel implements Serializable {
private static final long serialVersionUID = 2863256929817929825L;
private Integer id;
private Date createTime;
private Date lastmodifiedTime;
//省略 get set方法
/**
* 把对象转换成json字符
* 默认toString方法打印的是对象内存地址
*/
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
ToStringStyle的样式有很多种,大家可以自己试试别的样式,如JSON_STYLE。
在构造方法中打印了当前对象信息
public class Role extends BaseModel{
public Role(){}
public Role(String roleName, Date createDate){
this.roleName=roleName;
this.setCreateTime(createDate);
System.out.println(this);
}
private String roleName;
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public static void main(String[] args) {
new Role("admin",new Date());
}
}
运行结果如下
使用@ControllerAdvice注解接收全局信息
可以在@ExceptionHandler注解中指定处理的异常类
如果接口代码中没有try catch 异常的话,Exception类型的异常信息则会被ExceptionHndler方法处理
@ControllerAdvice
@Slf4j
public class GlobalExceptionController {
private static final String ERROR_MESSAGE = "系统内部错误,请联系管理员!";
@ExceptionHandler(value = Exception.class)
@ResponseBody
public String ExceptionHndler(Exception e) {
if (e instanceof FileNotFoundException) {
//可以自定义根据不同的异常类型,做一些代码处理
}
log.error("global error:{}", e);
return ERROR_MESSAGE;
}
}
我们可以通过aop来打印接口请求参数,返回结果,处理时间等信息.
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
1.9.5
org.aspectj
aspectjrt
${aspectj.version}
org.aspectj
aspectjweaver
${aspectj.version}
注解 | 功能描述 |
---|---|
@Aspect | 作用是把当前类标识为一个切面供容器读取 |
@Pointcut | Pointcut是植入Advice的触发条件。每个Pointcut的定义包括2部分,一是表达式,二是方法签名。方法签名必须是 public及void型。可以将Pointcut中的方法看作是一个被Advice引用的助记符,因为表达式不直观,因此我们可以通过方法签名的方式为 此表达式命名。因此Pointcut中的方法只需要方法签名,而不需要在方法体内编写实际代码。 |
@Around | 环绕增强,相当于MethodInterceptor |
@AfterReturning | 后置增强,相当于AfterReturningAdvice,方法正常退出时执行 |
@Before | 标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有 |
@AfterThrowing | 异常抛出增强,相当于ThrowsAdvice |
@After | final增强,不管是抛出异常或者正常退出都会执行 |
本文用到了@Aspect ,@Pointcut,@Around,@AfterThrowing|这4个注解.
编写一个切面类,然后通关@Pointcut注解指定要切入的方法
下面代码中用到了lombok插件,如果你没有使用的话,需要手动声明get set方法,还有log对象
@Aspect
@Slf4j
@Component
public class LogPointcut {
/**
* 对controller包下的所有类里的方法进行代理
*/
@Pointcut("execution(public * com.ljm.boot.simplifycode.controller.*.*(..)))")
public void requestServer(){
}
/**
* 环绕增强通知
*/
@Around("requestServer()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long start = System.currentTimeMillis();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Object result = proceedingJoinPoint.proceed();
RequestInfo requestInfo = new RequestInfo();
requestInfo.setIp(request.getRemoteAddr());
requestInfo.setUrl(request.getRequestURL().toString());
requestInfo.setHttpMethod(request.getMethod());
requestInfo.setClassMethod(String.format("%s.%s", proceedingJoinPoint.getSignature().getDeclaringTypeName(),
proceedingJoinPoint.getSignature().getName()));
requestInfo.setRequestParams(getRequestParamsByProceedingJoinPoint(proceedingJoinPoint));
requestInfo.setResult(result);
requestInfo.setTimeCost(System.currentTimeMillis() - start);
log.info("Request Info : {}", requestInfo);
return result;
}
/**
* 异常抛出增强
*/
@AfterThrowing(pointcut = "requestServer()", throwing = "e")
public void doAfterThrow(JoinPoint joinPoint, RuntimeException e) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
RequestErrorInfo requestErrorInfo = new RequestErrorInfo();
requestErrorInfo.setIp(request.getRemoteAddr());
requestErrorInfo.setUrl(request.getRequestURL().toString());
requestErrorInfo.setHttpMethod(request.getMethod());
requestErrorInfo.setClassMethod(String.format("%s.%s", joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName()));
requestErrorInfo.setRequestParams(getRequestParamsByJoinPoint(joinPoint));
requestErrorInfo.setException(e);
log.info("Error Request Info : {}", requestErrorInfo);
}
/**
* 获取入参
* @param proceedingJoinPoint
* */
private Map<String, Object> getRequestParamsByProceedingJoinPoint(ProceedingJoinPoint proceedingJoinPoint) {
//参数名
String[] paramNames = ((MethodSignature)proceedingJoinPoint.getSignature()).getParameterNames();
//参数值
Object[] paramValues = proceedingJoinPoint.getArgs();
return buildRequestParam(paramNames, paramValues);
}
private Map<String, Object> getRequestParamsByJoinPoint(JoinPoint joinPoint) {
//参数名
String[] paramNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();
//参数值
Object[] paramValues = joinPoint.getArgs();
return buildRequestParam(paramNames, paramValues);
}
private Map<String, Object> buildRequestParam(String[] paramNames, Object[] paramValues) {
Map<String, Object> requestParams = new HashMap<>(paramNames.length);
for (int i = 0; i < paramNames.length; i++) {
Object value = paramValues[i];
//如果是文件对象
if (value instanceof MultipartFile) {
MultipartFile file = (MultipartFile) value;
value = file.getOriginalFilename(); //获取文件名
}
requestParams.put(paramNames[i], value);
}
return requestParams;
}
@Data
public class RequestInfo implements Serializable {
private String ip; //ip地址
private String url; //请求路径
private String httpMethod; //方法类型
private String classMethod; //类和方法名称
private Object requestParams; //请求参数
private Object result; //返回的结果
private Long timeCost; //执行时长
}
@Data
public class RequestErrorInfo implements Serializable {
private String ip;
private String url;
private String httpMethod;
private String classMethod;
private Object requestParams;
private RuntimeException exception; //异常类型
}
}
@RestController
public class TestController {
@RequestMapping("/login")
public String login(@RequestBody User user){
if(user.getUsername().equals("admin") && user.getPassword().equals("123")){
return "登录成功";
}
return "登录失败";
}
}
public class TestPrint {
public static void main(String[] args) {
RestTemplate restTemplate=new RestTemplate();
HashMap param=new HashMap();
param.put("username","admin");
param.put("password","123");
String result=restTemplate.postForObject("http://localhost:8003/login",param,String.class);
System.out.println(result);
}
}
日志的完整json格式数据如下
RequestInfo:
LogPointcut.RequestInfo(
ip=127.0.0.1,
url=http: //localhost:8003/login,
httpMethod=POST,
classMethod=com.ljm.boot.simplifycode.controller.TestController.login,
requestParams={
user=User(username=admin,
password=123,
age=null)
},
result=登录成功,
timeCost=7
)
github地址
要是觉得我写的对你有点帮助的话,麻烦在github上帮我点 Star
【SpringBoot框架篇】其它文章如下,后续会继续更新。