5-2 用户模块-7个接口实现
- web端注册
- app端注册(所需参数更少)
- 登录
- 用户详情
- 修改密码
- 用户开关
- 修改用户信息
一、新增类
AppUserService.java
此类需定义和mapper层接口大致相同的方法(仅做返回值取舍,因为提供使用的对象不一样),被实现类实现后直接对访问接口提供能力,也就是供调用方进出
package com.a2j.service.user;
public interface AppUserService {
// 方法实现细节不做展开
}
AppUserImpl.java
该类为 AppUserService.java
接口的实现类,用于实现接口和数据库之间的主要逻辑,是逻辑处理最重要的一个类,记得加上 @Service
注解
package com.a2j.service.user;
// 标注service层,一定要在实现类,不能在service接口层
@Service
public class AppUserImpl implements AppUserService{
// 使用如下注解,注入mapper层对象引用
@Autowired
AppUserMapper mapper;
// 方法实现细节不做展开
}
AppUserController.java
package com.a2j.controller.user;
// 以下两个早就学过的用于controller的注解
@RestController
@RequestMapping("/user")
public class AppUserController {
@Autowired
AppUserService userService;
// 方法实现细节不做展开
}
二、请求方法
GetMapping
、PostMapping
、PutMapping
、DeleteMapping
- 通常选用规则:
仅查询用 GET,新增用 POST,修改用 PUT。较为复杂的入参建议使用 @RequestBody(如带分页的查询接口)
但有一种情况需要注意,@RequestBody最好不要和@GetMapping一起使用
否则你就会收获错误 “required request body is missing:...”
由于GET的参数是通过Url方式传递而不是请求体传递的,所以无法通过@RequestBody注解来接收(实际情况是我用postman测试可以,swagger调试报错)。
https://stackoverflow.com/questions/34956899/does-spring-requestbody-support-the-get-method
- PUT和POST是可以兼容使用的,使用方法如下:
@RequestMapping(value = "/xxx", method = {RequestMethod.POST, RequestMethod.PUT})
一、接口分类
使用上面的规则,针对接口进行分类:
查:GET
- 用户详情
增:POST
- web端注册
- app端注册(所需参数更少)
改:PUT
- 登录
- 修改密码
- 用户开关
- 修改用户信息
二、使用样例
- GetMapping
GET的参数拼接类似retrofit里的一种写法,使用@PathVariable
参数注解,标记url引用
@GetMapping("/userDetail/{id}")
public BaseBean<AppUser> appUserDetail(@PathVariable Integer id) {
return userService.appUserDetail(id);
}
- PostMapping
@PostMapping("/register")
public BaseBean<String> register(@RequestBody AppUser record) {
userService.register(record);
return BaseBean.success(ResponseCode.SUCCESS);
}
- PutMapping
@PutMapping("/login")
public BaseBean<AppUser> login(@RequestParam("account") String username, @RequestParam String password) {
return userService.login(username, password);
}
@RequestParam
注解有两个作用,定义如下
- 标记参数是否必传,默认必传
- 不想暴露内部参数名时,可以提供一个自定义的参数名给调用方
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean required() default true;
String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
}
三、重点提取
- @Service注解,一定要在实现类,不能在service接口层
- 必要参数用 @RequestParam 注解标记
- 不想暴露的参数使用 @RequestParam 重命名
四、举例错误排查
在调用测试的时候遇到错误,因为mapper层的接口方法还没和mapper.xml中SQL的id同步导致的:org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
出现这个问题有三种情况:
- mapper命名空间问题
- 方法名和id对不上
- 对象或者属性对不上
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.a2j.mapper.user.AppUserMapper.findUserByAccount
at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:235)
at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:53)
at org.apache.ibatis.binding.MapperProxy.lambda$cachedInvoker$0(MapperProxy.java:108)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
at org.apache.ibatis.util.MapUtil.computeIfAbsent(MapUtil.java:36)
at org.apache.ibatis.binding.MapperProxy.cachedInvoker(MapperProxy.java:95)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86)
at com.sun.proxy.$Proxy63.findUserByAccount(Unknown Source)
at com.a2j.service.user.AppUserImpl.register(AppUserImpl.java:31)
at com.a2j.controller.LoginController.register(LoginController.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1064)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)