Java阶段三Day07
文章目录
- Java阶段三Day07
- Spring Security
- 自定义UserDetails
- 密码加密
- 授权
- JDK包结构
- 文档注释规范
- JDK API
- String API
- String是不可变对象
- String常量池
- 内存编码及长度
- 使用indexOf实现检索
- 使用substring获取子串
- trim去除两侧空白
- charAt
- startsWith和endsWith
- 大小写变换
- valueOf
- StringBuilder API
- StringBuilder封装可变字符串
- StringBuilder常用方法
- StringBuild总结
- 教师总结
- 获取当前登录的用户信息
- 授权
Spring Security
自定义UserDetails
- 默认的
UserDetails
里面只有用户的用户名,没有其它的信息。如果需要用到类似id和nickname等信息的话需要自定义UserDetails
- 修改
UserDetailServiceImpl
中的UserDetails
,并把后期需要的id和nickName保存进去
UserDetailServiceImpl
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Resource
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserVO user = userMapper.selectByUsername(username);
if (user == null) {
return null; //默认抛出 AuthenticationException 用户名找不到异常
}
List<GrantedAuthority> list = AuthorityUtils.createAuthorityList("权限1", "权限2");
//创建自定义的UserDetails并把后期需要的id和nickName保存进去
CustomUserDetails userDetail = new CustomUserDetails(
user.getId(),
user.getNickname(),
username,
user.getPassword(),
list
);
//如果用户输入的密码和数据库中查询到的密码不一致则会抛出异常
return userDetail;
}
}
CustomUserDetails
@Getter
@ToString
public class CustomUserDetails extends User {
private Integer id;
private String nickname;
public CustomUserDetails(Integer id,String nickname,String username, String password, Collection<? extends GrantedAuthority> authorities) {
super(username, password, authorities);
this.id = id;
this.nickname = nickname;
}
}
WeiboController
@RestController
@RequestMapping("/v1/weibos")
public class WeiboController {
@Resource
private WeiboMapper weiboMapper;
@PostMapping("/insert")
public ResultVO reg(@RequestBody WeiboDTO weiboDTO, @AuthenticationPrincipal CustomUserDetails userDetails){
System.out.println("weiboDTO = " + weiboDTO + ", userDetails = " + userDetails);
Weibo weibo = new Weibo();
BeanUtils.copyProperties(weiboDTO, weibo);
weibo.setCreated(new Date());
//作者id 当前登录的用户id,从Security框架中得到当前登录的用户信息
weibo.setUserId(userDetails.getId());
weiboMapper.insert(weibo);
return new ResultVO(StatusCode.SUCCESS);
}
}
密码加密
- 在
SecurityConfig
配置类中配置密码加密方式return new BCryptPasswordEncoder();
- 在
UserController
中添加PasswordEncoder
自动装配,并在注册功能中对user对象里面的密码进行加密
SecurityConfig
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//配置密码加密的方式
@Bean
public PasswordEncoder passwordEncoder(){
//NoOpPasswordEncoder.getInstance()获取一个无加密的实例
//返回此加密的编码器之后, 用户输入的密码会通过此编码器加密之后再和数据库里面的密码进行比较
return new BCryptPasswordEncoder();
}
}
UserController
@RestController
@RequestMapping("/v1/users")
public class UserController {
@Autowired
PasswordEncoder passwordEncoder;
@Resource
private UserMapper userMapper;
@PostMapping("/reg")
public ResultVO reg(@RequestBody UserRegDTO userRegDTO){
UserVO userVO = userMapper.selectByUsername(userRegDTO.getUsername());
if(userVO!= null){
return new ResultVO(StatusCode.USERNAME_ALREADY_EXISTS);
}
User user = new User();
BeanUtils.copyProperties(userRegDTO, user);
user.setCreated(new Date());
//对user对象里面的密码进行加密 -- 加密之后得到60个字符长度的密码
user.setPassword(passwordEncoder.encode(user.getPassword()));
userMapper.insert(user);
return new ResultVO(StatusCode.SUCCESS);
}
}
授权
- 在
UserDetailsServicelmpl
中用户登录认证时,给当前用户设置拥有的权限 - 在
SecurityConfig
配置类中添加授权检测的注解@EnableGlobalMethodSecurity(prePostEnabled = true)
- 在
WeiboController
中处理请求的方法上面添加注解判断当前登录的用户是否拥有此权限,如果有,允许访问。如果没有则抛出异常 - 在统一全局异常处理
GlobalExceptionHandler
处理异常
UserDetailsServicelmpl
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Resource
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserVO user = userMapper.selectByUsername(username);
if (user == null) {
return null; //默认抛出 AuthenticationException 用户名找不到异常
}
//模拟王五是管理员,其他是用户
String role = username.equals("王五") ? "ADMIN" : "USER";
List<GrantedAuthority> list = AuthorityUtils.createAuthorityList(role);
//创建自定义的UserDetails并把后期需要的id和nickName保存进去
CustomUserDetails userDetail = new CustomUserDetails(
user.getId(),
user.getNickname(),
username,
user.getPassword(),
list
);
//如果用户输入的密码和数据库中查询到的密码不一致则会抛出异常
return userDetail;
}
}
SecurityConfig
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启方法授权的检测
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
WeiboController
@RestController
@RequestMapping("/v1/weibos")
public class WeiboController {
@Resource
private WeiboMapper weiboMapper;
@PostMapping("/{id}/delete")
//@PreAuthorize 当前用户必须拥有 ADMIN 权限才能删除,否则会抛出异常
@PreAuthorize("hasAnyAuthority('ADMIN')")
public ResultVO delete(@PathVariable Integer id){
weiboMapper.deleteById(id);
return new ResultVO(StatusCode.SUCCESS);
}
}
GlobalExceptionHandler
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 用户无权访问抛出异常
*/
@ExceptionHandler(AccessDeniedException.class)
public ResultVO handleAccessDeniedException(AccessDeniedException e){
log.warn("无权访问!");
return new ResultVO(StatusCode.FORBIDDEN_ERROR);
}
}
JDK包结构
-
为了便于使用和维护,JDK类库按照包结构划分,不同功能的类划分在不同的包中
-
经常使用的包如下表所示
包 功能 java.lang
Java程序的基础类,如字符串、多线程等,该包中的类使用的频率非常高,不需要import,可以直接使用 java.util
常用工具类,如集合、随机数产生器、日历、时钟等 java.io
文件操作、输入/输出操作 java.net
网络操作 java.math
数学运算相关操作 java.security
安全相关操作 java.sql
数据库访问 java.text
处理文字、日期、数字、信息的格式
文档注释规范
- 以
/**
开始,以*/
结束 - 加在类和方法的开头,用于说明作者,时间,版本,要实现功能的详细描述等信息
- 通过javadoc工具,可以轻松的将此注释转换为HTML文档说明;学习者和程序员主要通过文档了解API的功能
- 文档注释不同于普通的注释(/…或/…/),普通注释写在程序之中,用于程序员进行代码维护和交流,无法通过工具生成文档;而文档注释(/**…*/)写在类和方法的开头,专门用于生成供API使用者进行参考的文档资料
JDK API
String API
String是不可变对象
java.lang.String
使用了final修饰,不能被继承- 字符串底层封装了字符数组及针对字符数组的操作算法
- 字符串一旦创建,对象永远无法改变,但字符串引用可以重新赋值
- Java字符串在内存中采用Unicode编码方式,任何一个字符对应两个字节的定长编码。
String常量池
- Java为了提高性能,静态字符串(字面量 / 常量 / 常量连接的结果)在常量池中创建,并尽量使用同一个对象,重用静态字符串
- 对于重复出现的字符串直接量,JVM会首先在常量池中查找,如果存在即返回该对象。
内存编码及长度
- String在内存中采用Unicode编码,每个字符占用两个字节
- 任何一个字符(无论中文还是英文)都算1个字符长度,占用两个字节。
使用indexOf实现检索
-
indexOf
方法用于实现在字符串中检索另外一个字符串 -
String提供几个重载的
indexOf
方法方法 功能描述 int indexOf(String str) 在字符串中检索str,返回其第一次出现的位置,如果找不到则返回-1 int indexOf(String str,int fromIndex) 从字符串的 fromIndex位置开始检索 -
String还定义了
lastIndexOf
方法方法 功能描述 int lastIndexOf(String str,int from) str在字符串中多次出现时,将返回最后一个出现的位置
使用substring获取子串
-
substring
方法用于返回一个字符串的子字符串 -
substring
方法常用重载方法定义如下方法 功能描述 String substring(int beginIndex,int endIndex) 返回字符串中从下标beginlndex(包括)开始到endlndex(不包括)结束的子字符串 String substring(int beginIndex) 返回字符串中从下标beginIndex(包括)开始到字符串结尾的子字符串
trim去除两侧空白
trim方法用于去掉一个字符串的前导和后继空字符
charAt
方法 | 功能描述 |
---|---|
char charAt(int index) | 方法charAt()用于返回字符串指定位置的字符,参数index表示指定的位置 |
startsWith和endsWith
用于检测一个字符串是否以指定字符串开头或结尾
大小写变换
用于转换字符串中英文字母的大小写形式
valueOf
- String提供了若干的静态的重载方法
valueOf
- 该方法用于将其他类型转换为字符串类型
StringBuilder API
StringBuilder封装可变字符串
StringBuilder
封装可变的字符串,对象创建后可以通过调用方法改变其封装的字符序列StringBuilder
常用构造方法:- public StringBuilder()
- public StringBuilder(String str)
StringBuilder常用方法
常用方法 | 功能描述 |
---|---|
StringBuilder append(String str) | 追加字符串 |
StringBuilder append(int dstOffset,String s) | 插入字符串 |
StringBuilder append(int start,int end) | 删除字符串 |
StringBuilder replace(int start,int end,String str) | 替换字符串 |
StringBuilder reverse() | 字符串反转 |
StringBuild总结
-
StringBuilder
是可变字符串。字符串的内容计算,建议采用StringBuilder
实现,这样性能会好一些 -
java的字符串连接的过程是利用
StringBuilder
实现的String s = "AB" ;String s1 = s +"DE"+1; String s1 = new StringBuilder(s). append ( "DE")append(1).toString () ;
-
StringBuffer
和StringBuilder
StringBuffer
是线程安全的,同步处理的,性能稍慢StringBuilder
是非线程安全的,并发处理的,性能稍快
教师总结
获取当前登录的用户信息
-
如果需要获取用户名以外的信息, 需要自定义CustomUserDetails,
-
在UserDetailServiceImpl里面 把之前创建的UserDetails换成CustomUserDetails
-
在WeiboController中发微博的方法参数列表处声明CustomUserDetails,获取当前登录用户的信息
授权
-
在UserDetailsServiceImpl中 用户登录认证时,给当前用户设置拥有的权限
-
在Security配置类中添加授权检测的注解
-
在WeiboController中处理请求的方法上面添加注解 判断当前登录的用户是否拥有此权限,如果有,运行访问. 如果没有则抛出异常
-
在全局异常处理类中 处理异常