解决Day03中存在的问题
- 1. @ ResponseBody 与 @RequestBody
- 2. @RequestParam 与 @PathVariable
- 3. 字段填充技术(注解、AOP、反射)
- 3.1. AOP
- 3.2. 注解
- 3.3. 反射
- 3.5 字段填充在项目应用
- 4. 阿里云云存储OOS
1. @ ResponseBody 与 @RequestBody
@ResponseBody,用于将后端的JAVABEAN对象对象转化为JSON格式的数据返回给前端。
- 标注在控制器的方法上,用于将方法的返回值以JSON/XML的格式返回给客户端。
- 如果没有该注解,将返回一个ModelAndView给客户端,即返回视图。
- Spring中的新增注解:@RestController,
@RestController = @Controller + @ResponseBody
,如果一个Controller类添加了@RestController注解,那么该Controller类中的所有方法都相当于添加了@ResponseBody 注解。 - 当控制器使用@RestController标注时,控制器中的所有方法无需再添加@ResponseBody 注解;当控制器使用@Controller标注时,控制器中的所有方法则需要添加@ResponseBody注解。
@RequestBody,用于将前端发送来的JSON/XML格式的数据转化为JAVABEAN对象;
作用:
-
该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上;
-
再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上。
使用时机:
- GET、POST方式提时, 根据request header Content-Type的值来判断:
- application/x-www-form-urlencoded, 可选(即非必须,因为这种情况的数据@RequestParam, @ModelAttribute也可以处理,当然@RequestBody也能处理);
- multipart/form-data, 不能处理(即使用@RequestBody不能处理这种格式的数据);
- 其他格式, 必须(其他格式包括application/json, application/xml等。这些格式的数据,必须使用@RequestBody来处理);
- PUT方式提交时, 根据request header Content-Type的值来判断:
- application/x-www-form-urlencoded, 必须;
- multipart/form-data, 不能处理;
- 其他格式, 必须;
2. @RequestParam 与 @PathVariable
@RequestParam
和 @PathVariable
注解是用于从request
中接收请求的,两个都可以接收参数,关键点不同的是@RequestParam
是从request
里面拿取值,@PathVariable
是从一个url
模板里面来填充。
@RequestParam
// 请求方式1:http://127.0.0.1:8080/getUserId2?id=1 // id为1@PostMapping("getUserId2")
@ApiOperation(value = "获取Id2", notes = "通过用户ID获取")
public String findById2(@ApiParam(value = "用户ID", required = true) @RequestParam("id") Long id) {return "id为===》" + id;
}// 请求方式2:http://localhost:8080/springmvc/hello/101?param1=10¶m2=20public String getDetails(@RequestParam(value="param1", required=true) String param1,@RequestParam(value="param2", required=false) String param2){
...
}
@RequestParam 支持下面四种参数:
-
defaultValue 如果本次请求没有携带这个参数,或者参数为空,那么就会启用默认值
-
name 绑定本次参数的名称,要跟URL上面的一样
-
required 这个参数是不是必须的
-
value 跟name一样的作用,是name属性的一个别名
@PathVariable
// 请求方式1:http:// 127.0.0.1:8080/getUserId/1 // id为1@PostMapping("getUserId/{id}")
@ApiOperation(value = "获取Id", notes = "通过用户ID获取")
public String findById(@ApiParam(value = "用户ID", required = true) @PathVariable("id") Long id) {return "id为===》" + id;
}// http://localhost:8080/springmvc/hello/101?param1=10¶m2=20@RequestMapping("/hello/{id}")
public String getDetails(@PathVariable(value="id") String id, @RequestParam(value="param1", required=true) String param1,@RequestParam(value="param2", required=false) String param2){
.......
}
3. 字段填充技术(注解、AOP、反射)
3.1. AOP
查看个人博客详细介绍:
文章名称 | 笔记链接 | 简介 |
---|---|---|
Spring:AOP的核心概念(1) | https://lushimeng.blog.csdn.net/article/details/127962788 | 主要讲解AOP的一些概念,主要内容包括:AOP简介、AOP入门案例以及AOP工作的流程 |
Spring:AOP切入点表达式(2) | https://lushimeng.blog.csdn.net/article/details/127962794 | 主要描述切入点表达式、语法格式、通配符和书写技巧 |
Spring:AOP的五种通知类型(3) | https://lushimeng.blog.csdn.net/article/details/127962807 | 主要介绍AOP的五中通知类型:前置通知@Before、后置通知@After、环绕通知@Around、返回后通知@AfterReturning和异常后通知@AfterThrowing。主要掌握前后置和环绕通知类型 |
Spring:AOP通知获取数据(4) | https://lushimeng.blog.csdn.net/article/details/127962821 | 主要介绍AOP通知获取数据,主要分为两大块:AOP通知获取参数(非环绕获取和环绕获取) 和 AOP通知获取返回值(环绕通知获取和返回后通知获取) |
Spring:AOP事务管理(5) | https://lushimeng.blog.csdn.net/article/details/127962845 | 主要讲的是Spring事务管理,主要包括Spring事务简介、Spring事务以及Spring事务属性 |
3.2. 注解
查看个人博客详细介绍:Java单元测试、反射、注解、动态代理
3.3. 反射
查看个人博客详细介绍:Java单元测试、反射、注解、动态代理
3.5 字段填充在项目应用
存在问题:代码冗余、不便于后期维护
解决思路:字段填充技术。对于插入数据和更新数据分别加上不同的注解帮助自动填充字段信息。
- 自定义注解AutoFill,用于标识需要进行公共字段自动填充的方法
- 自定义切面类AutoFillAspect, 统一拦截加入了AutoFill注解的方法,通过反射为公共字段赋值
- 在Mapper的方法上加上AutoFillzhu注解
步骤一:自定义注解AutoFill
/*** 自定义注解,用于标识某个方法需要进行功能字段自动填充处理*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {// 数据库操作类型:insert, updateOperationType value();
}/*** 数据库操作类型*/
public enum OperationType {/*** 更新操作*/UPDATE,/*** 插入操作*/INSERT}
步骤二:自定义切面AutoFillAspect
/*** 自定义切面,实现公共字段自动填充处理逻辑*/
@Aspect
@Component
@Slf4j
public class AutoFillAspect {/*** 切入点*/@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")public void autoFillPointCut(){}/*** 前置通知,在通知总进行公共字段的赋值* @param joinPoint*/@Before("autoFillPointCut()")public void autoFill(JoinPoint joinPoint){log.info("开始进行公共字段自动填充....");}
}
完善autoFill方法
package com.sky.aspect;import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;/*** 自定义切面,实现公共字段自动填充处理逻辑*/
@Aspect
@Component
@Slf4j
public class AutoFillAspect {/*** 切入点*/@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")public void autoFillPointCut(){}/*** 前置通知,在通知总进行公共字段的赋值* @param joinPoint*/@Before("autoFillPointCut()")public void autoFill(JoinPoint joinPoint){log.info("开始进行公共字段自动填充....");// 获取到当前被拦截的方法上的数据库操作类型MethodSignature signature = (MethodSignature) joinPoint.getSignature(); // 方法签名对象AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class); // 获取方法上的注解OperationType operationType = autoFill.value(); // 获取数据库操作类型// 获取当前被拦截方法的参数--实体对象Object[] args = joinPoint.getArgs();if(args == null || args.length == 0){return;}Object entity = args[0]; // 获取参数实体对象,然后通过反射设置参数// 准备赋值数据LocalDateTime now = LocalDateTime.now();Long currentId = BaseContext.getCurrentId();// 根据当前不同的操作类型,为对应的属性通过反射来赋值if(operationType == OperationType.INSERT){try {Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);// 通过反射为对象属性赋值setCreateTime.invoke(entity, now);setUpdateTime.invoke(entity, now);setCreateUser.invoke(entity, currentId);setUpdateUser.invoke(entity, currentId);} catch (Exception e) {e.printStackTrace();}} else {try {Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);// 通过反射为对象属性赋值setUpdateTime.invoke(entity, now);setUpdateUser.invoke(entity, currentId);} catch (Exception e) {e.printStackTrace();}}}}
步骤三:在Mapper接口的方法上加入AutoFill注解并把业务层为公共字段赋值的代码注释掉
4. 阿里云云存储OOS
参考黑马2023年JavaWeb教程:黑马程序员JavaWeb开发教程 p148 文件上传-阿里云OOS