目录:
(1)websocket普通配置
(2)websocket有关JWT的配置
(3)websocket流程讲解
(4)个人中心功能实现
(5)自定义反序列化
(6)FastDFS工具类编写
(7)更新头像功能实现
(1)websocket普通配置
现在实现在线聊天的功能:
什么是在线聊天的功能呢,主要是为了方便大家把生活和工作给区分开,因为如果有在线聊天的话,咱们平时正常工作,在微信里面 有很多工作组,正常的生活跟工作是区分开的,那我们现在就有在线聊天,如果你是工作上找我的话,你可以通过在线聊天找我,私人找我,通过私人的聊天工具找我,尽量的把工作区分开,既然说到在线聊天,就需要说到WebSocket
引入依赖:
在config包下配置WebSocketConfig配置类:
(2)websocket有关JWT的配置
如果项目中没有使用到JWT,就不用配置中间这个方法了,但是我们项目中使用了JWT,所以需要配置,就是让我们获取到jwt令牌,然后作相应的处理,不然的话会被jwt登录拦截器拦截掉
package com.xxxx.server.config;
import com.xxxx.server.config.security.component.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
/**
* WebSocket配置类
*
* @author zhanglishen
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Value("${jwt.tokenHead}")
private String tokenHead;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private UserDetailsService userDetailsService;
/**
* 添加这个Endpoint,这样在网页可以通过websocket连接上服务
* 也就是我们配置websocket的服务地址,并且可以指定是否使用socketJS
* @param registry
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
/**
* 1.将ws/ep路径注册为stomp的端点,用户连接了这个端点就可以进行websocket通讯,支持
socketJS
* 2.setAllowedOrigins("*"):允许跨域
* 3.withSockJS():支持socketJS访问
*/
registry.addEndpoint("/ws/ep").setAllowedOrigins("*").withSockJS();
}
/**
* 输入通道参数配置
* @param registration
*/
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptor() {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
//判断是否为连接,如果是,需要获取token,并且设置用户对象
if (StompCommand.CONNECT.equals(accessor.getCommand())){
String token = accessor.getFirstNativeHeader("Auth-Token");
if (!StringUtils.isEmpty(token)){
String authToken = token.substring(tokenHead.length());
String username = jwtTokenUtil.getUserNameFromToken(authToken);
//token中存在用户名
if (!StringUtils.isEmpty(username)){
//登录
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
//验证token是都有效
if (jwtTokenUtil.validateToken(authToken,userDetails)){
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
accessor.setUser(authenticationToken);
}
}
}
}
return message;
}
});
}
/**
* 配置消息代理
* @param registry
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
//配置代理域,可以配置多个,配置代理目的地前缀为/queue,可以在配置域上向客户端推送消息
registry.enableSimpleBroker("/queue");
}
}
定义消息类:ChatMsg类
package com.xxxx.server.pojo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.security.core.parameters.P;
import java.time.LocalDateTime;
/**
* 消息
*
* @author zhanglishen
* @since 1.0.0
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
public class ChatMsg {
private String from;
private String to;
private String content;
private LocalDateTime date;
private String fromNickName;
}
创建Controller:WenSocketController:
package com.xxxx.server.controller;
import com.xxxx.server.pojo.Admin;
import com.xxxx.server.pojo.ChatMsg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import java.time.LocalDateTime;
@Controller
public class WenSocketController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/ws/chat")
public void handleMsg(Authentication authentication, ChatMsg chatMsg){
//获取当前登录对象
Admin admin = (Admin) authentication.getPrincipal();
chatMsg.setFrom(admin.getUsername());
chatMsg.setFromNickName(admin.getName());
chatMsg.setDate(LocalDateTime.now());
/**
* 发送消息
* 1.消息接收者
* 2.消息队列
* 3.消息对象
*/
simpMessagingTemplate.convertAndSendToUser(chatMsg.getTo(),"/queue/chat",chatMsg);
}
}
放行这个ws:
还要做一个处理,前端可以查询可以跟谁聊天创建controller:ChatController:
package com.xxxx.server.controller;
import com.xxxx.server.pojo.Admin;
import com.xxxx.server.service.IAdminService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/chat")
public class ChatController {
@Autowired
private IAdminService adminService;
@ApiOperation(value = "获取所有操作员")
@GetMapping("/")
public List<Admin> getAllAdmin(String keywords) {
return adminService.getAllAdmins(keywords);
}
}
(3)websocket流程讲解
(4)个人中心功能实现
个人中心做两部分内容,一个是个人中心的常规操作,另一个是更新头像,更新头像的时候会用到FastDFS
常规操作:1.查询当前登录用户的信息 2.更新当前用户的信息 3.更新密码
创建controller:AdminInfoController
package com.xxxx.server.controller;
import com.xxxx.server.pojo.Admin;
import com.xxxx.server.pojo.RespBean;
import com.xxxx.server.service.IAdminService;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
@RestController
public class AdminInfoController {
@Autowired
private IAdminService adminService;
@ApiOperation(value = "更新当前用户信息")
@PutMapping("/admin/info")
public RespBean updateAdmin(@RequestBody Admin admin, Authentication authentication) {
//更新成功,重新构建Authentication对象
if (adminService.updateById(admin)) {
/**
* 1.用户对象
* 2.凭证(密码)
* 3.用户角色
*/
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(admin, authentication.getCredentials(), authentication.getAuthorities()));
return RespBean.success("更新成功");
}
return RespBean.error("更新失败");
}
@ApiOperation(value = "更新用户密码")
@PutMapping("/admin/pass")
public RespBean updateAdminPassword(@RequestBody Map<String, Object> info) {
String oldPass = (String) info.get("oldPass");
String pass = (String) info.get("pass");
Integer adminId = (Integer) info.get("adminId");
return adminService.updatePassword(oldPass, pass, adminId);
}
}
更新密码:IAdminService:接口:
package com.xxxx.server.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xxxx.server.pojo.Admin;
import com.xxxx.server.pojo.Menu;
import com.xxxx.server.pojo.RespBean;
import com.xxxx.server.pojo.Role;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* <p>
* 服务类
* </p>
*
* @author zhanglishen
* @since 2022-08-05
*/
public interface IAdminService extends IService<Admin> {
//登录方法 登录之后返回token
RespBean login(String username, String password, String code, HttpServletRequest request);
//根据用户名获取用户
Admin getAdminByUserName(String username);
//根据用户id查询角色列表
List<Role> getRoles(Integer adminId);
//获取所有操作员
List<Admin> getAllAdmins(String keywords);
//更新操作员角色
RespBean updateAdminRole(Integer adminId, Integer[] rids);
//更新用户密码
RespBean updatePassword(String oldPass, String pass, Integer adminId);
}
实现类:
package com.xxxx.server.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxxx.server.AdminUtils;
import com.xxxx.server.config.security.component.JwtTokenUtil;
import com.xxxx.server.mapper.AdminMapper;
import com.xxxx.server.mapper.AdminRoleMapper;
import com.xxxx.server.mapper.RoleMapper;
import com.xxxx.server.pojo.Admin;
import com.xxxx.server.pojo.AdminRole;
import com.xxxx.server.pojo.RespBean;
import com.xxxx.server.pojo.Role;
import com.xxxx.server.service.IAdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.swing.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* 服务实现类
* </p>
*
* @author zhanglishen
* @since 2022-08-05
*/
@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements IAdminService {
//用到查数据库需要注入
@Autowired
private AdminMapper adminMapper;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
//注入工具类
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private RoleMapper roleMapper;
@Autowired
private AdminRoleMapper adminRoleMapper;
//通过注解去拿头部信息
@Value("${jwt.tokenHead}")
private String tokenHead;
//登录之后返回token
@Override
public RespBean login(String username, String password, String code, HttpServletRequest request) {
//获取验证码
String captcha =(String) request.getSession().getAttribute("captcha");
//判断 如果输入验证码为空或者输入的验证码不正确
if (StringUtils.isEmpty(code)||!captcha.equalsIgnoreCase(code)){
return RespBean.error("验证码输入错误,请重新输入!");
}
//登录
//获取到userDetaiils
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (null==userDetails||!passwordEncoder.matches(password,userDetails.getPassword())){
return RespBean.error("用户名或密码不正确");
}
if (!userDetails.isEnabled()){
return RespBean.error("账号被禁用!请联系管理员");
}
//更新security登录用户对象,把userDetails对象放到security全文中
UsernamePasswordAuthenticationToken authenticationToken=new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//生成token
//调用工具类的方法拿到token
String token = jwtTokenUtil.generateToken(userDetails);
Map<String,String> tokenMap=new HashMap<>();
tokenMap.put("token",token);
tokenMap.put("tokenHead",tokenHead);
return RespBean.success("登录成功",tokenMap);//把token返回给前端
}
//根据用户名获取
@Override
public Admin getAdminByUserName(String username) {
//使用MyBatis-plus查询
return adminMapper.selectOne(new QueryWrapper<Admin>().eq("username",username).eq("enabled",true));
}
//根据用户id查询角色列表
@Override
public List<Role> getRoles(Integer adminId) {
return roleMapper.getRoles(adminId);
}
//获取所有操作员
@Override
public List<Admin> getAllAdmins(String keywords) {
return adminMapper.getAllAdmins(AdminUtils.getCurrentAdmin().getId(), keywords);
}
//更新操作员角色
@Override
public RespBean updateAdminRole(Integer adminId, Integer[] rids) {
//先删除角色
adminRoleMapper.delete(new QueryWrapper<AdminRole>().eq("adminId",adminId));
//再添加角色
Integer result=adminRoleMapper.addAdminRole(adminId,rids);
if (rids.length==result){
return RespBean.success("更新成功!");
}
return RespBean.error("更新失败!");
}
//更新用户密码
@Override
public RespBean updatePassword(String oldPass, String pass, Integer adminId) {
Admin admin = adminMapper.selectById(adminId);
//加密
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
if (encoder.matches(oldPass,admin.getPassword())){
//设置新密码加密
admin.setPassword(encoder.encode(pass));
int i = adminMapper.updateById(admin);
if (i == 1){
return RespBean.success("更新成功");
}
}
return RespBean.error("更新失败");
}
}
(5)自定义反序列化
创建配置类:
package com.xxxx.server.config;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
* 自定义Authority
*/
public class CustomAuthorityDeserializer extends JsonDeserializer {
//反序列化方法
@Override
public Object deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
ObjectMapper mapper = (ObjectMapper) jsonParser.getCodec();
JsonNode jsonNode = mapper.readTree(jsonParser);
List<GrantedAuthority> grantedAuthorities = new LinkedList<>();
Iterator<JsonNode> elements = jsonNode.elements();
while (elements.hasNext()) {
JsonNode next = elements.next();
JsonNode authority = next.get("authority");
grantedAuthorities.add(new SimpleGrantedAuthority(authority.asText()));
}
return grantedAuthorities;
}
}
在Admin类中的加:@JsonDeserialize(using = CustomAuthorityDeserializer.class)
测试:
改为122:
改改后数据库:
更改用户密码:
更新成功之后需要重新登录
(6)FastDFS工具类编写
更新头像,用到了FastDFS,要更新头像的话需要确保FastDFS已经启动了,
引入依赖:
进行FastDFS的配置:
fdfs_client.conf:
#连接超时
connect_timeout = 2
#网络超时
network_timeout = 30
#编码格式
charset = UTF-8
#tracker端口号
http.tracker_http_port = 8080
#防盗链功能
http.anti_steal_token = no
#秘钥
http.secret_key = FastDFS1234567890
#tracker ip:端口号
tracker_server = 192.168.23.129:22122
#连接池配置
connection_pool.enabled = true
connection_pool.max_count_per_entry = 500
connection_pool.max_idle_time = 3600
connection_pool.max_wait_time_in_ms = 1000
FastDFSUtils:工具类
package com.xxxx.server.utils;
import org.csource.fastdfs.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 文件上传工具类
*
* @author zhanglishen
* @since 1.0.0
*/
public class FastDFSUtils {
//使用日志
private static Logger logger = LoggerFactory.getLogger(FastDFSUtils.class);
//初始化客户端
static {
try {
String filePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();
//读取配置文件,并初始化对应的属性
ClientGlobal.init(filePath);
} catch (Exception e) {
logger.error("初始化FastDFS失败 ",e);
}
}
/**
* 上传文件
* @param file
* @return
*/
public static String[] upload(MultipartFile file){
//获取文件的名字
String filename = file.getOriginalFilename();
logger.info("文件名 :" + filename);
long startTime = System.currentTimeMillis();
String[] uploadResults = null;
StorageClient storageClient = null;
//获取storage客户端
try {
storageClient = getStorageClient();
//上传
try {
uploadResults = storageClient.upload_file(file.getBytes(),filename.substring(filename.lastIndexOf(".")+1),null);
} catch (IOException e) {
logger.error("IO Exception when uploadind the file:" + filename, e);
}
} catch (Exception e) {
logger.error("Non IO Exception when uploadind the file:" + filename, e);
}
logger.info("upload_file time used:" + (System.currentTimeMillis() - startTime) + " ms");
//验证上传结果
if (uploadResults == null && storageClient != null){
logger.error("上传失败:" + storageClient.getErrorCode());
}
//上传成功返回groupName
logger.info("上传传文件成功!!!" + "group_name:" + uploadResults[0] + ", remoteFileName:" + " " + uploadResults[1]);
return uploadResults;
}
/**
* 获取文件信息
* @param groupName
* @param remoteFileName
* @return
*/
public static FileInfo getFileInfo(String groupName,String remoteFileName){
try {
StorageClient storageClient = getStorageClient();//客户端
return storageClient.get_file_info(groupName,remoteFileName);
} catch (IOException e) {
logger.error("IO Exception: Get File from Fast DFS failed", e);
}catch (Exception e) {
logger.error("文件获取失败!!", e);
}
return null;
}
/**
* 下载
* @param groupName
* @param remoteFileName
* @return
*/
public static InputStream downFile(String groupName,String remoteFileName){
try {
StorageClient storageClient = getStorageClient();//客户端
byte[] bytes = storageClient.download_file(groupName, remoteFileName);
InputStream inputStream = new ByteArrayInputStream(bytes);//将数组转换为流
return inputStream;
} catch (IOException e) {
logger.error("IO Exception: Get File from Fast DFS failed", e);
}catch (Exception e) {
logger.error("文件下载失败!!!", e);
}
return null;
}
/**
* 删除文件
* @param groupName
* @param remoteFileName
* @throws Exception
*/
public static void deleteFile(String groupName,String remoteFileName) throws Exception {
StorageClient storageClient = null;
try{
storageClient=getStorageClient();
int i = storageClient.delete_file(groupName, remoteFileName);
logger.info("文件删除成功" + i);
}catch (Exception e){
logger.info("文件删除失败" + e.getMessage());
}
}
/**
* 生成Storage客户端
* @return
*/
private static StorageClient getStorageClient() throws IOException {
TrackerServer trackerServer = getTrackerServer();
StorageClient storageClient = new StorageClient(trackerServer, null);
return storageClient;
}
/**
* 生成Tracker服务器端
* @return
*/
private static TrackerServer getTrackerServer() throws IOException {
TrackerClient trackerClient = new TrackerClient();
TrackerServer trackerServer = trackerClient.getTrackerServer();
return trackerServer;
}
/**
* 获取文件路径
* @return
*/
public static String getTrackerUrl(){
TrackerClient trackerClient = new TrackerClient();
TrackerServer trackerServer = null;
StorageServer storageServer = null;
try {
trackerServer = trackerClient.getTrackerServer();
storageServer = trackerClient.getStoreStorage(trackerServer);
} catch (Exception e) {
logger.info("文件路径获取失败" + e.getMessage());
}
return "http://"+storageServer.getInetSocketAddress().getHostString() + ":8888/";
}
}
(7)更新头像功能实现
AdminInfoController:
package com.xxxx.server.controller;
import com.xxxx.server.pojo.Admin;
import com.xxxx.server.pojo.RespBean;
import com.xxxx.server.service.IAdminService;
import com.xxxx.server.utils.FastDFSUtils;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
@RestController
public class AdminInfoController {
@Autowired
private IAdminService adminService;
@ApiOperation(value = "更新当前用户信息")
@PutMapping("/admin/info")
public RespBean updateAdmin(@RequestBody Admin admin, Authentication authentication) {
//更新成功,重新构建Authentication对象
if (adminService.updateById(admin)) {
/**
* 1.用户对象
* 2.凭证(密码)
* 3.用户角色
*/
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(admin, authentication.getCredentials(), authentication.getAuthorities()));
return RespBean.success("更新成功");
}
return RespBean.error("更新失败");
}
@ApiOperation(value = "更新用户密码")
@PutMapping("/admin/pass")
public RespBean updateAdminPassword(@RequestBody Map<String, Object> info) {
String oldPass = (String) info.get("oldPass");
String pass = (String) info.get("pass");
Integer adminId = (Integer) info.get("adminId");
return adminService.updatePassword(oldPass, pass, adminId);
}
@ApiOperation(value = "更新用户头像")
@PostMapping("/admin/userface")
public RespBean updateUserFace(MultipartFile file, Integer id, Authentication authentication) {
//获取文件上传地址
String[] uploadPath = FastDFSUtils.upload(file);
//完整的url
String url = FastDFSUtils.getTrackerUrl() + uploadPath[0] + "/" + uploadPath[1];
return adminService.updateAdminUserFace(url,id,authentication);
}
}
IAdminService接口:
package com.xxxx.server.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xxxx.server.pojo.Admin;
import com.xxxx.server.pojo.Menu;
import com.xxxx.server.pojo.RespBean;
import com.xxxx.server.pojo.Role;
import org.springframework.security.core.Authentication;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* <p>
* 服务类
* </p>
*
* @author zhanglishen
* @since 2022-08-05
*/
public interface IAdminService extends IService<Admin> {
//登录方法 登录之后返回token
RespBean login(String username, String password, String code, HttpServletRequest request);
//根据用户名获取用户
Admin getAdminByUserName(String username);
//根据用户id查询角色列表
List<Role> getRoles(Integer adminId);
//获取所有操作员
List<Admin> getAllAdmins(String keywords);
//更新操作员角色
RespBean updateAdminRole(Integer adminId, Integer[] rids);
//更新用户密码
RespBean updatePassword(String oldPass, String pass, Integer adminId);
//更新用户头像
RespBean updateAdminUserFace(String url, Integer id, Authentication authentication);
}
实现类:
package com.xxxx.server.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxxx.server.utils.AdminUtils;
import com.xxxx.server.config.security.component.JwtTokenUtil;
import com.xxxx.server.mapper.AdminMapper;
import com.xxxx.server.mapper.AdminRoleMapper;
import com.xxxx.server.mapper.RoleMapper;
import com.xxxx.server.pojo.Admin;
import com.xxxx.server.pojo.AdminRole;
import com.xxxx.server.pojo.RespBean;
import com.xxxx.server.pojo.Role;
import com.xxxx.server.service.IAdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* 服务实现类
* </p>
*
* @author zhanglishen
* @since 2022-08-05
*/
@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements IAdminService {
//用到查数据库需要注入
@Autowired
private AdminMapper adminMapper;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
//注入工具类
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private RoleMapper roleMapper;
@Autowired
private AdminRoleMapper adminRoleMapper;
//通过注解去拿头部信息
@Value("${jwt.tokenHead}")
private String tokenHead;
//登录之后返回token
@Override
public RespBean login(String username, String password, String code, HttpServletRequest request) {
//获取验证码
String captcha =(String) request.getSession().getAttribute("captcha");
//判断 如果输入验证码为空或者输入的验证码不正确
if (StringUtils.isEmpty(code)||!captcha.equalsIgnoreCase(code)){
return RespBean.error("验证码输入错误,请重新输入!");
}
//登录
//获取到userDetaiils
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (null==userDetails||!passwordEncoder.matches(password,userDetails.getPassword())){
return RespBean.error("用户名或密码不正确");
}
if (!userDetails.isEnabled()){
return RespBean.error("账号被禁用!请联系管理员");
}
//更新security登录用户对象,把userDetails对象放到security全文中
UsernamePasswordAuthenticationToken authenticationToken=new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//生成token
//调用工具类的方法拿到token
String token = jwtTokenUtil.generateToken(userDetails);
Map<String,String> tokenMap=new HashMap<>();
tokenMap.put("token",token);
tokenMap.put("tokenHead",tokenHead);
return RespBean.success("登录成功",tokenMap);//把token返回给前端
}
//根据用户名获取
@Override
public Admin getAdminByUserName(String username) {
//使用MyBatis-plus查询
return adminMapper.selectOne(new QueryWrapper<Admin>().eq("username",username).eq("enabled",true));
}
//根据用户id查询角色列表
@Override
public List<Role> getRoles(Integer adminId) {
return roleMapper.getRoles(adminId);
}
//获取所有操作员
@Override
public List<Admin> getAllAdmins(String keywords) {
return adminMapper.getAllAdmins(AdminUtils.getCurrentAdmin().getId(), keywords);
}
//更新操作员角色
@Override
public RespBean updateAdminRole(Integer adminId, Integer[] rids) {
//先删除角色
adminRoleMapper.delete(new QueryWrapper<AdminRole>().eq("adminId",adminId));
//再添加角色
Integer result=adminRoleMapper.addAdminRole(adminId,rids);
if (rids.length==result){
return RespBean.success("更新成功!");
}
return RespBean.error("更新失败!");
}
//更新用户密码
@Override
public RespBean updatePassword(String oldPass, String pass, Integer adminId) {
Admin admin = adminMapper.selectById(adminId);
//加密
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
if (encoder.matches(oldPass,admin.getPassword())){
//设置新密码加密
admin.setPassword(encoder.encode(pass));
int i = adminMapper.updateById(admin);
if (i == 1){
return RespBean.success("更新成功");
}
}
return RespBean.error("更新失败");
}
//更新用户头像
@Override
public RespBean updateAdminUserFace(String url, Integer id, Authentication authentication) {
Admin admin = adminMapper.selectById(id);
admin.setUserFace(url);
int i = adminMapper.updateById(admin);
if (i == 1){
//全局对象更新
Admin principal = (Admin) authentication.getPrincipal();
principal.setUserFace(url);
//更新Authentication
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(admin,authentication.getCredentials(),authentication.getAuthorities()));
return RespBean.success("更新成功",url);
}
return RespBean.error("更新失败");
}
}
重新启动主启动类:
选择文件:
storage里面的文件
点击发送:
发现storager存储节点里面多了图片