演示
代码定义
UserService.java 定义了函数 findByUserName()
public interface UserService {
User findByUserName(String userName);
}
UserServiceImpl.java 是实现类,通过UserMapper.java / UserMapper.xml 实现查询功能。
@Service
public class UserServiceImpl implements UserService {
private InformationVerification informationVerification = new InformationVerification();
@Autowired
UserMapper userMapper;
@Override
public User findByUserName(String userName) {
return (userMapper.selectByUserName(userName) != null ? userMapper.selectByUserName(userName) : null);
}
}
UserMapper.java
@Component
public interface UserMapper {
User selectByUserName(String userName);
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.test.mapper.UserMapper">
...
<select id="selectByUserName" resultType="com.test.entity.User">
SELECT * FROM user WHERE userName = #{userName};
</select>
</mapper>
UserService -> UserServiceImpl -> UserMapper.java -> UserMapper.xml
以上是各个文件之间的依赖关系。
实现方式1
@RestController
@RequestMapping("test/user")
public class UserController {
@Autowired
UserService userService;
@GetMapping("findByUserName")
public Result<User> findByUserName(@RequestParam("userName") String userName) {
return new Result<User>().success(userService.findByUserName(userName));
}
}
通过@Autowired注入。
实现方式2
@RestController
@RequestMapping("test/user")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("findByUserName")
public Result<User> findByUserName(@RequestParam("userName") String userName) {
return new Result<User>().success(userService.findByUserName(userName));
}
}
final + 构造函数,完成注入。
实现方式3
@RestController
@RequestMapping("test/user")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@GetMapping("findByUserName")
public Result<User> findByUserName(@RequestParam("userName") String userName) {
return new Result<User>().success(userService.findByUserName(userName));
}
}
利用Lombok插件的@RequiredArgsConstructor,完成构造函数。
准确的说,实现方式2与实现方式3是同一种方法,只不过方式3借助Lombok简化了代码而已。
为何使用final修饰成员变量?
Springboot官方建议使用final来修饰成员变量,然后通过构造方法来进行注入。
注意:final修饰的成员变量是不能够被修改的,
1. 防止已经注入的成员变量被修改。
2. 避免以后因修改代码,例如将方法的返回值更新为null,而造成恶劣影响。
Lombok 构造器注解
注解 | 构造函数参数 | 非空校验 | 备注 |
@NoArgsConstructor | 无参 | 无 | 可使用参数 |
@RequiredArgsConstructor | 未初始化的final字段、标注为nonnull的字段 | 有 | 可使用参数@RequiredArgsConstructor(staticName = “of”),将构造方法私有化,并提供静态函数of创建构造函数。 |
@AllArgsConstrutor | 所有字段有可使用参数 | 有 | @AllArgsConstrutor(access = AccessLevel.PROTECTED)来控制构造函数的访问级别。 |
- @NoArgsConstructor
@NoArgsConstructor
用于生成无参构造函数。如果因为final字段未初始化导致构造失败,则会导致编译失败。可以使用@NoArgsConstructor(force
= true)参数,从而强制将未初始化的fianl字段赋值为 0 / false / null。 对于具有约束的字段(例如 @NonNull 字段),不会进行检查。因此请注意,正确初始化这些字段之前,这些约束无效。
- @RequiredArgsConstructor
@RequiredArgsConstructor
为有需要特殊处理的字段生成带有一个参数的构造函数,所有未能初始化的fianl字段,以及被标记为@NonNull且在声明时没有初始化的字段,都是该构造函数的参数。
参数的顺序与类中字段出现的顺序是保持一致的,对于@NonNull的字段也会进行空值检查,如果不符合校验规则,抛出空指针异常。
- @AllArgsConstructor
@AllArgsConstructor:为类中的每个字段生成一个具有1个参数的构造函数。 标记为@Non Null的字段会进行空值检查。