前置
完成<从零学习javaWeb> 2. 数据表设计和三层架构的操作后,根据接口文档实现一些简单的Controller层接口,并用IDEA进行测试。
1. 登录逻辑
1.1 接口文档
- 接收参数:用户账号、密码
- 请求类型:POST
- 请求体:JSON格式
- 返回值:用户信息(脱敏)
1.2 逻辑
-
账号密码是否合法
- 非空
- 长度
- 特殊字符
-
密码是否正确
-
用户信息脱敏
-
记录登录态(seesion),调
HttpServletRequest
的接口java//记录session request.getSession().setAttribute(USER_LOG_STATE, newUser);
1.3 Controller层实现
1.3.1 实现的方法
- 注册(上期在Service层实现)
- 登录
1.3.2 知识点
- 多个参数的请求可以单独封装成一个请求实体类,如注册接收三个字符串,将这三个字符串封装到UserRegisterRequest中
- 用@Date自动生成一个实体类的get和set等
- @RestController修饰Controller层的类,方便其接收和响应http请求,其包括@Controller,修饰类并创建bean;还有@ResponseBody,表示返回值都要直接写入响应体。
- @ReuqestMapping修饰Controller层的类,定义其相对路径,不同方法内再用@PostMapping等定义下一级路径
- @RequestBody修饰Controller层方法的形参,自动将参数从JSON转换成相应的对象。
- 在Controller层,基本只做对参数的校验和调Service层接口,做到尽量的解耦
1.3.3 实现
java
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
@PostMapping("/register")
public Long userRegister(@RequestBody UserRegisterRequest userRegisterRequest){
if(userRegisterRequest == null){
return null;
}
String userAccount = userRegisterRequest.getUserAccount();
String userPassword = userRegisterRequest.getUserPassword();
String checkPassword = userRegisterRequest.getCheckPassword();
if(StringUtils.isAnyBlank(userAccount,userPassword,checkPassword)){
return null;
}
return userService.userRegister(userAccount, userPassword, checkPassword);
}
@PostMapping("/login")
public User userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request){
if(userLoginRequest == null){
return null;
}
String userAccount = userLoginRequest.getUserAccount();
String userPassword = userLoginRequest.getUserPassword();
if(StringUtils.isAnyBlank(userAccount,userPassword)){
return null;
}
return userService.userLogin(userAccount, userPassword, request);
}
}
1.3.4 测试
可以用IDEA自带的测试工具:
-
点击对应方法左边的http客户端打开
-
写请求头和参数
jsonPOST http://localhost:8080/user/login Content-Type: application/json { "userAccount" : "lzj33", "userPassword" : "123456789" }
-
启动后端服务器,发送请求,配合断点调试和查看返回值
2. 管理员逻辑
2.1接口文档
2.1.1 根据用户名查询用户
- 接收参数:用户名
- 接收参数类型:String
- 请求类型:GET
- 请求体类型:String
- 返回值:
List<User>
用户信息(脱敏)
2.1.2 根据用户id删除用户
- 接收参数:用户id
- 接收参数类型:int
- 请求类型:POST
- 请求体类型:int
- 返回值:
boolean
是否删除成功
2.2 知识点
- 需要做用户鉴权,从session中取出当前登录用户的信息,判断是否为管理员(userRole==1)
- 返回的用户信息需要脱敏
- 重复的代码(10行以上)提取为方法,如两个接口都有用户鉴权,可以提取为公共方法提高代码复用性
- 常量可以提取到一个接口中存储
2.3 实现
2.3.1 用户鉴权
java
public boolean isAdmin(HttpServletRequest request){
Object userObj = request.getSession().getAttribute(USER_LOG_STATE);
User user = (User)userObj;
if(user != null && user.getUserRole()==ADMIN_ROLE){
return true;
}
return false;
}
2.3.2 用户脱敏
java
public User getSafetyUser(User user){
user.setUserPassword(null);
return user;
}
2.3.3 查询和删除接口
java
@GetMapping("/search")
public List<User> searchUsers(String userName, HttpServletRequest request){
if(!isAdmin(request)){
return null;
}
List<User> users = userService.searchUserByName(userName);
return users;
}
@PostMapping("/delete")
public boolean deleteUser(@RequestBody long id, HttpServletRequest request){
if(!isAdmin(request)){
log.info("permission denied: not admin");
return false;
}
if(id<=0){
return false;
}
return userService.removeById(id);
}
3. 前端设置
前端使用ant-design pro脚手架快捷开发,页面原型已有,需要根据接口文档做一定修改
3.1 实现
3.1.1 修改请求
- 修改请求的路径,在api.ts中有各个接口对应的路径,修改成对应的后端路径
- 修改请求的参数:一个是前端中对应的变量名,还有一个是请求体真正传递的变量名
- 修改返回值的处理:由于后端返回的是user信息,将前端改成相应的处理(user是否为空)
- 修改代理:由于前端是8000端口,后端是8080端口,会有跨域问题。用其自带的代理配置可以完成跳转
- 后端全局路径配置:由于前端设置的请求路径是/api/xxx,后端需要给所有请求加一个/api的前缀,可以在application.xml中配置:
java
server:
port: 8080
servlet:
context-path: /api
3.2 测试
3.2.1 错误示例
3.2.2 成功示例
总结
- 后端三层架构下的接口开发、代码优化(冗余代码提取成方法、常量类)
- 常见SpringBoot注解的使用、Session的使用
- Mybatis-plus的使用,包括一键生成domain对象、mapper和service
- 后端测试:IDEA自带的http client,POST和GET的参数传递
- 断点测试:F7步入、F8逐步、F9恢复
- 前端代理和与后端参数、路径的对齐。