package cn.mypandora.springboot.modular.system.service.impl;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import com.github.pagehelper.PageHelper;
import cn.mypandora.springboot.config.exception.BusinessException;
import cn.mypandora.springboot.config.exception.EntityNotFoundException;
import cn.mypandora.springboot.config.exception.StorageException;
import cn.mypandora.springboot.core.base.PageInfo;
import cn.mypandora.springboot.core.enums.StatusEnum;
import cn.mypandora.springboot.core.util.FileUtil;
import cn.mypandora.springboot.core.util.JsonWebTokenUtil;
import cn.mypandora.springboot.modular.system.mapper.DepartmentUserMapper;
import cn.mypandora.springboot.modular.system.mapper.UserMapper;
import cn.mypandora.springboot.modular.system.mapper.UserRoleMapper;
import cn.mypandora.springboot.modular.system.model.po.*;
import cn.mypandora.springboot.modular.system.model.vo.JwtAccount;
import cn.mypandora.springboot.modular.system.model.vo.Token;
import cn.mypandora.springboot.modular.system.service.ResourceService;
import cn.mypandora.springboot.modular.system.service.RoleService;
import cn.mypandora.springboot.modular.system.service.UserService;
import lombok.extern.slf4j.Slf4j;
import tk.mybatis.mapper.entity.Example;
/**
* UserServiceImpl
*
* @author hankaibo
* @date 2019/6/14
*/
@Slf4j
@Service
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
private final UserRoleMapper userRoleMapper;
private final DepartmentUserMapper departmentUserMapper;
private RoleService roleService;
private ResourceService resourceService;
private StringRedisTemplate stringRedisTemplate;
@Value("${upload.path}")
private String dirPath;
@Value("${upload.remote-url}")
private String remoteUrl;
@Autowired
public UserServiceImpl(UserMapper userMapper, UserRoleMapper userRoleMapper,
DepartmentUserMapper departmentUserMapper, RoleService roleService, ResourceService resourceService,
StringRedisTemplate stringRedisTemplate) {
this.userMapper = userMapper;
this.userRoleMapper = userRoleMapper;
this.departmentUserMapper = departmentUserMapper;
this.roleService = roleService;
this.resourceService = resourceService;
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
public Token login(String username) {
User user = getUserByName(username);
Long userId = user.getId();
// 获取角色信息
Map<String, String> roleMap = getRoles(username);
String roleCodes = roleMap.get("code");
String roleIds = roleMap.get("id");
// 获取资源信息
String resourceCodes = getResourceCodes(username);
// 时间以秒计算,token有效刷新时间是token有效过期时间的2倍
long refreshPeriodTime = 36000L;
// 生成jwt并将签发的JWT存储到Redis: {JWT-ID-{username} , jwt}
String jwt = JsonWebTokenUtil.createJwt(UUID.randomUUID().toString(), "token-server", username,
refreshPeriodTime >> 1, userId, roleIds, roleCodes, resourceCodes);
stringRedisTemplate.opsForValue().set(StringUtils.upperCase("JWT-ID-" + username), jwt, refreshPeriodTime,
TimeUnit.SECONDS);
// 返回给前台数据
Token token = new Token();
token.setToken(jwt);
token.setRoles(roleCodes);
token.setResources(resourceCodes);
return token;
}
@Override
public void logout(String authorization) {
SecurityUtils.getSubject().logout();
String jwt = JsonWebTokenUtil.unBearer(authorization);
JwtAccount jwtAccount = JsonWebTokenUtil.parseJwt(jwt);
String username = jwtAccount.getAppId();
if (StringUtils.isEmpty(username)) {
throw new EntityNotFoundException(User.class, "Authorization错误,用户为空。");
}
String jwtInRedis = stringRedisTemplate.opsForValue().get(StringUtils.upperCase("JWT-ID-" + username));
if (StringUtils.isEmpty(jwtInRedis)) {
throw new EntityNotFoundException(User.class, "token为空。");
}
stringRedisTemplate.opsForValue().getOperations().delete(StringUtils.upperCase("JWT-ID-" + username));
}
@Override
public PageInfo<User> pageUser(int pageNum, int pageSize, User user, Long departmentId) {
PageHelper.startPage(pageNum, pageSize);
List<User> userList = userMapper.pageUser(user, departmentId);
userList.forEach(item -> {
item.setPassword(null);
item.setSalt(null);
});
return new PageInfo<>(userList);
}
@Override
public String saveFile(MultipartFile file) {
return FileUtil.saveFile(file, dirPath, remoteUrl);
}
@Override
public User getUserByName(String username) {
Example user = new Example(User.class);
user.createCriteria().andEqualTo("username", username);
User info = userMapper.selectOneByExample(user);
if (info == null) {
throw new EntityNotFoundException(User.class, "用户不存在。");
}
return info;
}
@Override
public User getUserById(Long id) {
// 查询用户
User info = userMapper.selectByPrimaryKey(id);
if (info == null) {
throw new EntityNotFoundException(User.class, "用户不存在。");
}
// 避免密码被返回给页面
info.setSalt(null);
info.setPassword(null);
// 查询用户所在部门
DepartmentUser departmentUser = new DepartmentUser();
departmentUser.setUserId(id);
List<DepartmentUser> departmentUserList = departmentUserMapper.select(departmentUser);
List<Long> departmentIdList = new ArrayList<>();
for (DepartmentUser du : departmentUserList) {
departmentIdList.add(du.getDepartmentId());
}
info.setDepartmentIdList(departmentIdList);
// 转换用户头像地址
back2FrontPath(info);
return info;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void addUser(User user) {
LocalDateTime now = LocalDateTime.now();
user.setCreateTime(now);
user.setLastLoginTime(null);
passwordHelper(user);
// 转换用户头像地址
front2BackPath(user);
// 添加用户
userMapper.insert(user);
// 添加用户部门关联
if (user.getDepartmentIdList().size() > 0) {
List<DepartmentUser> departmentUserList = new ArrayList<>();
for (Long departmentId : user.getDepartmentIdList()) {
DepartmentUser departmentUser = new DepartmentUser();
departmentUser.setDepartmentId(departmentId);
departmentUser.setUserId(user.getId());
departmentUser.setCreateTime(now);
departmentUserList.add(departmentUser);
}
departmentUserMapper.insertList(departmentUserList);
}
}
@Transa