学习目标
1.controller的完善
利用@RequestBody
使用时,方法的请求方式必须是post
,将参数设置为json格式
在发送时,采用Context-Type为application/json方式传递参数
后端接收到json字符串后,再利用jackson(默认的springboot整合的json解析工具)解析json字符串
核心方法ObjectMapper
对返回结果的增强–R类
2.java操作数据(DAO 持久层)
jdbc
MyBatis
MyBatis-Plus
今日所学
更新项目目录
1.swagger的使用加强
@Api 对控制器本身进行描述 声明在控制器类中
@Api(value="UserController",tags="用户操作接口")
public void class UserController{}
@ApiOperation 对参数进行描述
@ApiOperation(value = "register",tags = "用户注册方法",notes = "用户注册注意事项")
public User register(UserRegisterDto dto){}
@ApiParam 声明在参数中
public User getByid(@ApiParam Integer id){}
@ApiImplicitParam 声明在方法中
@ApiImplicitParams 声明在方法中,包含多个@ApiImplicitParam
@ApiImplicitParams({
@ApiImplicitParam(value = "id",name = "用户id")
})
public User getByid(Integer id){}
@ApiModel 对实体类增强描述
@ApiModelProperties
@ApiModel(value = "UserDto",description = "用户对象Dto传输数据")
public class UserDto implements Serializable {
@ApiModelProperty(value = "phone",name = "用户手机号")
private String phone;
@ApiModelProperty(value = "pwd",name = "用户密码")
private String pwd;
}
2.接口设计中的约定
1.所有方法的返回类型都是R
2.简单的查询方法中(getByid)使用get
请求方式
3.复杂的参数情况用dto对象封装,如果有敏感字段就应该使用json(请求类型为post
)
4.查询一般用GET
请求方式,而增删改操作一般用POST
请求方式
5.复杂的查询用dto封装查询条件(查询特征/分页特征)要用POST
请求方式
6.restful风格的开发方式
get 查询 http://localhost:8080/user/1
post 添加 http://localhost:8080/user
put 修改 http://localhost:8080/user
delete 删除 http://localhost:8080/user/1
//以编号为1的用户做CRUD操作
//查询
GET http://localhost:8080/user/1
@GetMapping("/{id}")
public void select(@PathVariable("id") Integer id){}
//删除
DELETE http://localhost:8080/user/1
@DeleteMapping("/{id}")
public Boolean delete(@PathVariable("id") Integer id){}
//添加
POST http://localhost:8080/user
@PostMapping("")
public Boolean insert(@RequestBody UserDto dto){}
//修改
POST http://localhost:8080/user
@PutMapping("")
public Boolean update(@RequestBody UserDto dto){}
3.Controller的增强
异常处理
初步方案
利用try-catch
进行异常处理,相对于throws,好处在于try-catch
可以在方法内部局部处理异常,而不是将异常传递给调用者。这样可以更灵活地处理异常,根据具体情况选择如何处理异常,而不是强制调用者处理。
但是当不知道异常可能存在哪个语句中,就需要将所有语句都放在try
中,这样就造成了代码的复杂冗余,也使代码可读性降低。
PostMapping("/login")
public R login(@RequestBody UserDto dto) {
try{
int i = 1/0;
UserVo vo = null;
if("133".equals(dto.getPhone()) && "123456".equals(dto.getPwd())){
// 登录成功
vo = new UserVo();
vo.setId(1);
vo.setName("张三丰");
vo.setPhone("13312345678");
vo.setPwd("123456");
// 使用UUID来快速生成一个给前端颁发的token串
String token = UUID.randomUUID().toString().replaceAll("-","");
vo.setToken(token);
}
return vo!=null? R.success(vo) : R.error();
}catch (Exception e){
return R.error("系统开小差了, 请稍后再试");
}
}
优化处理
使用封装方式
AOP(面向切面编程)(底层原理:动态代理)
由于我们知道每次都需要用到try-catch
,那么我们有理由猜想可以将try-catch
代码块进行封装,形成一个所谓的模板
@PostMapping("/login")
public R ****(@RequestBody UserDto dto) {
try{
...
}catch (Exception e){
return R.error("系统开小差了, 请稍后再试");
}
}
采用全局异常处理器
1.@RestControllerAdvice
:聚合注解,结合了@ControllerAdvice
和@ResponseBody
,用于定义全局异常处理类,并将处理结果直接返回给客户端。
2.@ExceptionHandler(Throwable.class)
:异常处理方法,用于捕获所有Throwable
类型的异常,即所有可能抛出的异常都会被这个方法捕获。
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Throwable.class)
public R handler(){
return R.error("系统开小差了, 请稍后再试");
}
}
4.实现在控制器中进行功能处理
创建普通类封装方法
一个接口的设计成功/失败都具有一个统一的返回类型:R(自己命名)
R中包括的信息:code(状态码)/msg(后端返回给前端的信息)/data(数据)…
@Data
public class R implements Serializable {
private Integer code;
private String msg;
private Object data;
public static R success(){
R r = new R();
r.setCode(200);
r.setMsg("success");
return r;
}
public static R success(Object data){
R r = new R();
r.setData(data);
return r;
}
public static R failed(){
R r = new R();
r.setCode(0);
r.setMsg("failed");
return r;
}
public static R failed(String msg){
R r = new R();
r.setCode(0);
r.setMsg(msg);
return r;
}
}
自定义异常类
public class BizException extends Exception{
public BizException(ErrorCode errorCode){
super(errorCode.getMsg());
}
}
全局异常处理控制器
@RestControllerAdvice
public class GlobalExceptionHander {
@ExceptionHandler(BizException.class)
public R handerBizException(BizException e){
return R.failed(e.getMessage());
}
@ExceptionHandler(Throwable.class)
public R handerThoowable(){
return R.failed("服务器开小差,请稍后再试...");
}
}
创建枚举类
注意:枚举常量的名字需要全大写
public enum ErrorCode {
ERROR_LOGIN(501,"登陆失败,用户名或密码错误"),
ERROR_USER(502,"查询用户不存在"),
ERROR_REGISTER(503,"该手机号已经被注册了")
;
private Integer code;
private String msg;
ErrorCode(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
查找方法
简单利用id进行查找用户
如果id值大于5那么返回用户不存在的信息(因为还没涉及到数据库,所以简单练习一下全局异常处理器,下面也是同理)
@GetMapping("/getByid")
public User getByid(Integer id) throws BizExceptio
User user = new User();
user.setId(id);
user.setName("张三丰");
user.setPhone("123");
user.setPwd("12345
if (id > 5){
throw new BizException(ErrorCode.ERROR_USER);
return user;
查找检测
登陆方法
通过给定的电话和密码去判断用户登陆信息是否正确
@PostMapping("/login")
@ApiOperation(value = "用户登陆方法",notes ="{\n" +
" \"phone\": \"123\",\n" +
" \"pwd\": \"12345\"\n" +
"}")
public R login(@RequestBody UserDto dto) throws BizException{
UserVo userVo = null
if ("123".equals(dto.getPhone()) && "12345".equals(dto.getPwd())){
userVo = new UserVo;
userVo.setId(1);
userVo.setName("张三丰");
userVo.setPhone("123");
userVo.setPwd("12345");
String token = UUID.randomUUID().toString().replaceAll("-","");
userVo.setToken(token);
if (userVo == null){
throw new BizException(ErrorCode.ERROR_LOGIN);
return R.success(userVo);
}
登陆检测
注册方法
简单实现如果输入框内容不为空即可注册成功
判断如果注册电话是133,那么返回一个电话已经被注册的信息
@PostMapping("/register")
@ApiOperation(value = "register",tags = "用户注册方法",notes = "{\n" +
" \"name\": \"zhangsan\",\n" +
" \"phone\": \"123\",\n" +
" \"pwd\": \"12345\"\n" +
"}")
public R register(@RequestBody UserRegisterDto dto) throws BizException {
User user = null;
if (!"".equals(dto.getName()) && !"".equals(dto.getPhone()) && !"".equals(dto.getPwd())){
user = new User();
//利用Spring框架的工具类进行数据复制
BeanUtils.copyProperties(dto,user);
}
if ("133".equals(user.getPhone())){
throw new BizException(ErrorCode.ERROR_REGISTER);
}
return R.success(user);
}
注册检测
5.动态代理
作用
在java程序编译或运行期间动态生成一个对象
分类
jdk动态代理
cglib动态代理
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class UserMapperProxy {
// 通过动态代理生成UserMapper的实例
public void test(){
// Proxy 代理类
// newProxyInstance 创建代理对象的方法
// 类加载器的实例
ClassLoader classLoader = this.getClass().getClassLoader();
// interfaces
Class[] interfaces = {UserMapper.class};
UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(classLoader,
interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
return method.invoke(proxy,args);
}
});
userMapper.getById(1);
}
}