1.第一步先安装一个nacous注册中心,用一个简单的单机windos版本就行,也可以使用Linux下的redis集群版本,两种选择
然后在需要运行的服务器配置文件下配置指定注册中心
spring:
application:
#应用名称, 向注册中心注册的名称
name: GatewayServer
cloud:
nacos:
discovery:
#注册中心地址
server-addr: http://localhost:8848/
2.配置gateway_server代理服务器
跨域请求配置和代理服务器
spring:
application:
#应用名称, 向注册中心注册的名称
name: GatewayServer
cloud:
gateway:
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "*" #所有网站
#- "http://localhost:8090" #指定网站
#- "http://www.leyou.com"
allowedMethods: # 允许的跨域ajax的请求方式
- "*"
#- "GET"
#- "POST"
#- "DELETE"
#- "PUT"
#- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期
routes:
# - 连续多个配置,前面用-
# 随便命名 是当前路由的唯一标识 不可以重复 最好和服务名称有关
- id: member_route
# 配置请求的服务的地址
#uri: http://localhost:14221
# 配置请求的服务名称,必须和要访问服务注册到注册中心的名称一致
uri: lb://MemberServer
# 断言配置 满足下面配置的所有条件 请求才会继续
predicates:
#路径必须正确
- Path=/order/**,/member/**
#允许哪些restful类型
- Method=GET,POST,PUT,DELETE
- Query=id,\d+ #要有参数id并且要求id为整数
- Before=2023-02-22T11:25:40.666+08:00[Asia/Shanghai] #匹配这个时间之前的请求 UTC时间,也就是国际统一时间 +8:00 东八区
- After=2021-02-21T12:15:30.666+08:00[Asia/Shanghai] #匹配这个时间之后的请求
- Between=2021-02-21T12:15:30.666+08:00[Asia/Shanghai],2023-02-21T12:15:30.666+08:00[Asia/Shanghai]
#自定义非法IP
illegal_ip:
#配置白名单(不进行拦截的地址)
white_list: /userLogin/authUser,/memberLogin/authMember,/userLogin/chechAccessToken,/member/sentSM,/member/insert
2.2需要在启动时,自己注入HttpMessageConverters
/**
* @ fileName:WebFluxWithOpenFeignConfig
* @ description: gateway整合openfeign时,会报错误,
* * 查看错误堆栈 HttpMessageConverters 没有被注入到容器中管理
* * 需要在启动时,自己注入HttpMessageConverters
* @ author:zhz
* @ createTime:2022/3/11 16:03
* @ version:1.0.0
*/
@Configuration
public class WebFluxWithOpenFeignConfig {
/**
* 实例化HttpMessageConverters
* @param converters
* @return
*/
@Bean
@ConditionalOnMissingBean
public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));
}
}
2.3字符过滤器
@Component
//@Order(3)
public class IllegalCharFilter implements GlobalFilter,Ordered{
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("经过了非法字符过滤器。。。。。。。。。。。");
//让程序继续运行
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 10;
}
}
2.4IP过滤器
@Component
public class IllegalIpFilter implements GlobalFilter, Ordered {
@Value("${illegal_ip}")
private String illegalIp;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("经过了非法IP过滤器。。。。。。。。。。。");
//通过过滤方法提供的参数获取request,response
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//通过request 获取IP
InetSocketAddress remoteAddress = request.getRemoteAddress();
InetAddress address = remoteAddress.getAddress();
String hostAddress = address.getHostAddress();
System.out.println(hostAddress+"........hostAddress...............");
//判断请求的IP是否在拦截IP列表中
if(illegalIp.contains(hostAddress)){
// 不合法则返回错误信息
Map<String, Object> map = new HashMap<>();
map.put("errorCode", ResultStatus.ILLEGAL_IP.getCode());
map.put("errorMessage", ResultStatus.ILLEGAL_IP.getMessage());
try {
byte[] datas = JSON.toJSONString(map).getBytes("utf-8");
DataBuffer buffer = response.bufferFactory().wrap(datas);
//添加响应头
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
//写入自定义错误信息,并返回
return response.writeWith(Mono.just(buffer));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
//让程序继续运行
return chain.filter(exchange);
}
/**
*
* @return 执行的级别,小的先执行
*/
@Override
public int getOrder() {
return 5;
}
}
2.5白名单放行
@Component
public class RedirectLoginFilter implements GlobalFilter, Ordered {
@Resource
private RemoLoginService remoLoginService;
@Value("${white_list}")
private String whiteList;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("经过了转发登录过滤器。。。。。。。。。。。");
//通过过滤方法提供的参数获取request,response
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//获取请求携带所有参数 /member/selectOne/1?a=1&b=2&c=3&accessToken=admin131321dafadf11
MultiValueMap<String, String> queryParams = request.getQueryParams();
//获取IP
String hostAddress = request.getRemoteAddress().getAddress().getHostAddress();
System.out.println("-----------hostAddress-------"+hostAddress);
String requestPath = request.getPath().toString();
System.out.println("------------requestPath------------"+requestPath);
if(requestPath.contains("/userLogin/authUser")){
Set<Map.Entry<String, List<String>>> entryList = queryParams.entrySet();
String userName=null;
String passWord=null;
for (Map.Entry<String, List<String>> stringListEntry : entryList) {
if(stringListEntry.getKey().equals("userName")){
userName=stringListEntry.getValue().get(0);
}
if(stringListEntry.getKey().equals("passWord")){
passWord=stringListEntry.getValue().get(0);
}
}
System.out.println("转发登录请求。。。。。。。。。。。。。"+userName+","+passWord+","+hostAddress);
Result result = remoLoginService.authUser(userName, passWord, hostAddress);
try {
byte[] datas = JSON.toJSONString(result).getBytes("utf-8");
DataBuffer buffer = response.bufferFactory().wrap(datas);
//添加响应头
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
//写入自定义错误信息,并返回
return response.writeWith(Mono.just(buffer));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
//让程序继续运行
return chain.filter(exchange);
}
/**
*
* @return
*/
@Override
public int getOrder() {
return 6;
}
}
2.6Sso单点登录过滤
@Component
public class SsoLoginFilter implements GlobalFilter, Ordered {
@Resource
private RemoLoginService remoLoginService;
@Value("${white_list}")
private String whiteList;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("经过了单点登录过滤器。。。。。。。。。。。");
//通过过滤方法提供的参数获取request,response
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//获取请求路径
RequestPath requestPath = request.getPath();
System.out.println(requestPath.toString()+"........requestPath...............");
//分割白名单
String[] whitePathArray = whiteList.split(",");
for (String whitePath : whitePathArray) {
//如果是白名单 直接放行
if(requestPath.toString().contains(whitePath)){
return chain.filter(exchange);
}
}
//获取请求携带所有参数 /member/selectOne/1?a=1&b=2&c=3&accessToken=admin131321dafadf11
MultiValueMap<String, String> queryParams = request.getQueryParams();
//循环遍历,查看参数中是否含有accessToken 如果含有获取它对应的值,做校验
// entries [a=1,b=2...accessToken=admin13]
Set<Map.Entry<String, List<String>>> entries = queryParams.entrySet();
//定义accessToken
String accessToken = null;
for (Map.Entry<String, List<String>> entry : entries) {
//第一次 a=1 第二次 b=2 ...
if("accessToken".equals(entry.getKey())){
accessToken=entry.getValue().get(0);
break;
}
}
//获取IP
String hostAddress = request.getRemoteAddress().getAddress().getHostAddress();
boolean isTrue = remoLoginService.checkAccessToken(accessToken,hostAddress);
//判断accessToken是否为空
if(accessToken==null || !isTrue){
// 不合法则返回错误信息
Map<String, Object> map = new HashMap<>();
map.put("errorCode", ResultStatus.TOKEN_NOT_NULL.getCode());
map.put("errorMessage", ResultStatus.TOKEN_NOT_NULL.getMessage());
try {
byte[] datas = JSON.toJSONString(map).getBytes("utf-8");
DataBuffer buffer = response.bufferFactory().wrap(datas);
//添加响应头
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
//写入自定义错误信息,并返回
return response.writeWith(Mono.just(buffer));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
//让程序继续运行
return chain.filter(exchange);
}
/**
*
* @return
*/
@Override
public int getOrder() {
return 8;
}
}
3.配置单点登录
3.1.单点登录配置文件配置和shiro配置
#当前服务端口号
server:
port: 14288
# servlet:
# #配置上下文对象 访问的项目名称
# context-path: /ordera
#阿里druid连接池配置
spring:
application:
#应用名称 一定配置,作用是注册到注册中心的名称,其他服务调用时,都是根据该名称调用
name: SsoServer
cloud:
nacos:
discovery:
#配置nacos注册中心地址
server-addr: http://localhost:8848
redis:
host: 127.0.0.1
port: 6379
#连接属性配置
database: 0
timeout: 30000ms
jedis:
pool:
max-active: 20000
max-idle: 0
max-wait: 20000ms
# cluster:
# nodes: 192.168.170.166:6001,192.168.170.166:6002
#swagger配置
swagger:
base-package: com.aaa.sso.controller
title: "租车项目-单点登录模块"
description: "描述"
version: "3.0"
contact:
name: "AAA"
email: "[email protected]"
url: "https://www.baidu.com"
terms-of-service-url: "服务条款:https://www.baidu.com"
@Configuration
public class SpringShiroConfig {
/**
* 实例化过滤工厂类(配置拦截路径及放行路径,配置使用SecurityManager等)
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(){
//实例化
ShiroFilterFactoryBean shiroFilterFactoryBean = new
ShiroFilterFactoryBean();
//配置使用SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager());
//实例化参数对象(LinkedHashMap 先后配置顺序读取)
Map<String, String> pathMap = new LinkedHashMap<>();
//anon 放行 authc 拦截 loginOut 退出。。。
pathMap.put("/**","anon");
//配置拦截或者放行路径
shiroFilterFactoryBean.setFilterChainDefinitionMap(pathMap);
return shiroFilterFactoryBean;
}
/**
* shiro核心组件 安全管理组件 认证和授权的后台管理类
* @return
*/
@Bean
public SecurityManager securityManager(){
//实例化 SecurityManager子类,web应用使用
DefaultWebSecurityManager securityManager =new DefaultWebSecurityManager();
//设置自定义认证器
securityManager.setAuthenticator(customModularRealmAuthenticator());
//设置安全数据链接桥梁 Realm
//securityManager.setRealm(myRealm());
List<Realm> realmList = new ArrayList<>();
realmList.add(memberRealm());
realmList.add(userRealm());
securityManager.setRealms(realmList);
return securityManager;
}
/**
* 设置自定义认证器(认证策略为一个realm成功及成功)
* @return
*/
@Bean
public CustomModularRealmAuthenticator customModularRealmAuthenticator(){
CustomModularRealmAuthenticator customModularRealmAuthenticator
=new CustomModularRealmAuthenticator();
//配置认证策略,两个realm 只要有一个认证成功,都可以访问资源
//无论是手机端或者管理端,登录认证后,都可以访问所有资源
customModularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
return customModularRealmAuthenticator;
}
/**
* 自定义MemberRealm类
* @return
*/
@Bean
public MemberRealm memberRealm(){
//实例化安全数据链接桥梁
MemberRealm memberRealm =new MemberRealm();
//设置加密算法类
memberRealm.setCredentialsMatcher(credentialsMatcher());
return memberRealm;
}
/**
* 自定义userRealm类
* @return
*/
@Bean
public UserRealm userRealm(){
//实例化安全数据链接桥梁
UserRealm userRealm =new UserRealm();
//设置加密算法类
userRealm.setCredentialsMatcher(credentialsMatcher());
return userRealm;
}
/**
* 加密算法类
* @return
*/
@Bean
public CredentialsMatcher credentialsMatcher(){
HashedCredentialsMatcher credentialsMatcher =
new HashedCredentialsMatcher();
//设置加密算法名称
credentialsMatcher.setHashAlgorithmName(BusinessConstant.CredentialsMatcher.ALGORITHM_NAME);
//设置hash次数
credentialsMatcher.setHashIterations(BusinessConstant.CredentialsMatcher.HASH_ITERATIONS);
return credentialsMatcher;
}
}
3.2根据登录路径访问到单点controller层
/**
* @ fileName:UserLoginController
* @ description: 用户登录控制器
* @ author:zhz
* @ createTime:2022/3/10 16:55
* @ version:1.0.0
*/
@RestController
@RequestMapping("userLogin")
public class UserLoginController {
//@Resource(name = "memberAuthService")
@Autowired
@Qualifier("userAuthService")
private AuthService authService;
/**
* 会员验证功能
* @param userName
* @param passWord
* @return
*/
@GetMapping("authUser")
public Result authUser(String userName, String passWord,String remoteIp){
return authService.authMemberOrUser(userName,passWord,remoteIp);
}
/**
* 验证token
* @param accessToken
* @return
*/
@GetMapping("checkAccessToken")
public boolean checkAccessToken(@RequestParam("accessToken") String accessToken,@RequestParam("remoteIp") String remoteIp){
return authService.chechAccessToken(accessToken,remoteIp);
}
}
3.3到实现类层
//用于判断是登录的类型
@Service("userAuthService")
public class UserAuthServiceImpl implements AuthService{
//依赖注入request对象
@Resource
private HttpServletRequest request;
//依赖注入redis模板类
@Resource
private RedisTemplate redisTemplate;
@Override
public Result authMemberOrUser(String userName, String passWord,String remoteIp) {
//收集用户信息
CustomUsernamePasswordToken customUsernamePasswordToken =
new CustomUsernamePasswordToken(userName, passWord, LoginType.USER.toString());
//获取主体
Subject subject = SecurityUtils.getSubject();
try {
//登录
subject.login(customUsernamePasswordToken);
//获取认证成功后的用户对象
User user = (User)subject.getPrincipal();
//生成token
String accessToken = userName+ UUID.randomUUID().toString();
//获取用户访问IP和accessToken 加密运算得到一个加密值,存入到redis中
//获取 访问IP
// String remoteAddr = request.getRemoteAddr();
System.out.println("......remoteAddr..........."+remoteIp);
//存入redis
//设置底层存储为字符串序列化
redisTemplate.setKeySerializer(new StringRedisSerializer());
//存储新登录的token前,删除以前的token
Set keys = redisTemplate.keys(userName + "*");
// 循环删除
for (Object key : keys) {
redisTemplate.delete(key);
}
redisTemplate.opsForValue().set(accessToken,user,3, TimeUnit.DAYS);
redisTemplate.opsForValue().get(accessToken);
System.out.println("!11111111111111111111111111111111111111");
System.out.println("!11111111111111111111111111111111111111");
User o = (User)redisTemplate.opsForValue().get(accessToken);
System.out.println("++++++++++++++++++++"+o.getUserId());
System.out.println("我是token+++++++++++++++++++++++++"+redisTemplate.opsForValue().get(accessToken));
// 使用获取的IP和生成的token进行加密运算,得到加密值也要存储
Sha512Hash sha512Hash = new Sha512Hash(remoteIp,accessToken,10);
//也要存储redis
redisTemplate.opsForValue().set(accessToken+"CheckToken",sha512Hash.toString());
//记录登录日志
System.out.println("================"+accessToken);
//返回token
return new Result(ResultStatus.SUCCESS.getCode(),ResultStatus.SUCCESS.getMessage(),
accessToken);
} catch (AuthenticationException e) {
e.printStackTrace();
}
return new Result(ResultStatus.ERROR_USERNAME_PASSWORD.getCode(),
ResultStatus.ERROR_USERNAME_PASSWORD.getMessage(),null);
}
@Override
public boolean chechAccessToken(String accessToken,String remoteIp) {
redisTemplate.setKeySerializer(new StringRedisSerializer());
Boolean aBoolean = redisTemplate.hasKey(accessToken);
if(!aBoolean){
return false;
}
//获取 访问IP
//String remoteAddr = request.getRemoteAddr();
System.out.println("-------远程ip--------"+remoteIp);
// 使用获取的IP和生成的token进行加密运算,得到加密值也要存储
Sha512Hash sha512Hash = new Sha512Hash(remoteIp,accessToken,10);
//获取原来存储的值
Object saveRemoteIPAndTokenValue = redisTemplate.opsForValue().get(accessToken + "CheckToken");
//进行比对
if(sha512Hash.toString().equals(saveRemoteIPAndTokenValue.toString())){
return true;
}
return false;
}
}
3.3 login触发单点登录shiro认证,进入领域
public class UserRealm extends AuthorizingRealm {
@Resource
private RemoteUserService remoteUserService;
/**
* 获取授权数据的方法
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 获取认证数据单点方法
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取收集到用户名
String userName = (String)authenticationToken.getPrincipal();
//根据用户名获取对象
Result result = remoteUserService.queryUserByUserName(userName);
// 失败,说明用户错没有获取到用户信息
if(result.getCode()==500){
throw new AccountException();
}
//转换User
User user = JSON.parseObject(JSON.toJSONString(result.getData()), User.class);
return new SimpleAuthenticationInfo(user,
user.getPassword(),
ByteSource.Util.bytes(user.getSalt()),
getName());
}
}
3.4认证之后会触发认证方法执行,应为是多服务器需要远程调用,上面是接口,下面是远程方法
@FeignClient(value = "SystemServer")
public interface RemoteUserService {
/**
* 根据用户名查询用户信息
* @param phoneNum
* @return
*/
@GetMapping("/user/selectUserByUserName")
Result queryUserByUserName(@RequestParam("phoneNum") String phoneNum);
}
@GetMapping("selectUserByUserName")
public Result selectUserByUserName(@RequestParam("phoneNum") String phoneNum){
//封装查询
QueryWrapper<User> queryWrapper =new QueryWrapper<>();
queryWrapper.eq("del_flag",0);
queryWrapper.eq("status",0);
queryWrapper.eq("user_name",phoneNum);// where user_name='隔壁老王'
//查询列表
List<User> userList = userService.list(queryWrapper);
//判断
if(CollUtil.isNotEmpty(userList)){
return new Result(ResultStatus.SUCCESS.getCode(),
ResultStatus.SUCCESS.getMessage(),userList.get(0));
}
return new Result(ResultStatus.ERROR.getCode(),
ResultStatus.ERROR.getMessage(),"没有用户信息");
}
3.5区分领域认证类型实现类
public class CustomUsernamePasswordToken extends UsernamePasswordToken {
private String loginType;
/**
* 自定CustomUsernamePasswordToken 区分是用户还是会员
* @param username
* @param password
* @param loginType
*/
public CustomUsernamePasswordToken(String username, String password, String loginType) {
super(username, password);
this.loginType = loginType;
}
public String getLoginType() {
return loginType;
}
public void setLoginType(String loginType) {
this.loginType = loginType;
}
}
3.6单多realm判断
public class CustomModularRealmAuthenticator extends ModularRealmAuthenticator {
@Override
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
// 判断getRealms()是否返回为空
assertRealmsConfigured();
// 强制转换回自定义的CustomizedToken 多态 向下转型
CustomUsernamePasswordToken customizedToken = (CustomUsernamePasswordToken) authenticationToken;
// 登录类型
String loginType = customizedToken.getLoginType();
// 所有Realm
Collection<Realm> realms = getRealms();
System.out.println(realms+"..realm对象..");
// 登录类型对应的所有Realm
Collection<Realm> typeRealms = new ArrayList<>();
for (Realm realm : realms) {
if (realm.getName().contains(loginType)){
typeRealms.add(realm);
}
}
// 判断是单Realm还是多Realm
if (typeRealms.size() == 1){
//单realm认证
return doSingleRealmAuthentication(typeRealms.iterator().next(), customizedToken);
}
else{
//多realm认证
return doMultiRealmAuthentication(typeRealms, customizedToken);
}
}
}
4.权限服务器配置后台配置
4.1配置文件配置
#当前服务端口号
server:
port: 14270
# servlet:
# #配置上下文对象 访问的项目名称
# context-path: /ordera
#阿里druid连接池配置
spring:
datasource:
druid:
url: jdbc:mysql://localhost:3306/qy142crms?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: root
password: zzgsxygwb
initial-size: 1
max-active: 20
min-idle: 10
max-wait: 10
application:
#应用名称 一定配置,作用是注册到注册中心的名称,其他服务调用时,都是根据该名称调用
name: SystemServer
cloud:
nacos:
discovery:
#配置nacos注册中心地址
server-addr: http://localhost:8848
mybatis-plus:
# mapper.xml配置
mapper-locations: classpath:mapper/*.xml
configuration:
#控制台日志输出配置
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#别名包配置
type-aliases-package: com.aaa.system.entity
#swagger配置
swagger:
base-package: com.aaa.system.controller
title: "租车项目-会员模块-订单swagger"
description: "描述"
version: "3.0"
contact:
name: "AAA"
email: "[email protected]"
url: "https://www.baidu.com"
terms-of-service-url: "服务条款:https://www.baidu.com"
4.2菜单服务实现类和sql语句
/**
* 菜单权限表(Menu)表服务实现类
*
* @author makejava
* @since 2022-03-11 20:10:43
*/
@Service("menuService")
public class MenuServiceImpl extends ServiceImpl<MenuDao, Menu> implements MenuService {
@Resource
private MenuDao menuDao;
@Resource
private RedisTemplate redisTemplate;
/**
* 根据用户编号查询树形数据(用户登录后左侧树菜单数据)
* @return
*/
@Override
public List<TreeNode> queryTreeDataByUserId(String accessToken) {
// System.out.println("queryTreeDataByUserId,sessionId-------"+session.getId());
// User user = (User)session.getAttribute("userInfo");
//查询所有数据
// redisTemplate.opsForValue().set(accessToken,user,3, TimeUnit.DAYS);
System.out.println("hhhhhhhhhhhhhhhhhhhhhhhhhhhh");
// User accessToken1 = (User)redisTemplate.opsForValue().get(accessToken);
// Integer userId = accessToken1.getUserId();
redisTemplate.setKeySerializer(new StringRedisSerializer());
// System.out.println(userId+" 111111111111111111111111111111111");
System.out.println("!11111111111111111111111111111111111111");
System.out.println("!11111111111111111111111111111111111111");
User o = (User)redisTemplate.opsForValue().get(accessToken);
System.out.println("++++++++++++++++++++"+o.getUserId());
List<TreeNode> treeNodes = menuDao.queryTreeDataByUserId(o.getUserId());
//List<TreeNode> treeNodes = menuDao.queryTreeDataByUserId(user.getUserId());
//定义一个返回的结果集
List<TreeNode> tempTreeNodes = new ArrayList<>();
//拼装为树形数据
if(treeNodes!=null&&treeNodes.size()>0){
//循环遍历
for (com.aaa.common.entity.TreeNode treeNode : treeNodes) {
//查找一级节点
if(treeNode.getParentId()==0){
tempTreeNodes.add(treeNode);
//为一级的所有子节点查找并绑定孩子
findAndBindChild(treeNode,treeNodes);
}
}
}
return tempTreeNodes;
}
/**
* 所有的树形菜单数据
* @return 单条数据
*/
@Override
public List<TreeNode> queryAllTreeData() {
//查询所有数据
List<TreeNode> treeNodes = menuDao.queryAllTreeData();
//定义一个返回的结果集
List<TreeNode> tempTreeNodes = new ArrayList<>();
//拼装为树形数据
if(treeNodes!=null&&treeNodes.size()>0){
//循环遍历
for (TreeNode treeNode : treeNodes) {
//查找一级节点
if(treeNode.getParentId()==0){
tempTreeNodes.add(treeNode);
//为一级的所有子节点查找并绑定孩子
findAndBindChild(treeNode,treeNodes);
}
}
}
return tempTreeNodes;
}
/**
* 为所有子节点查找并绑定孩子
* @param currentTreeNode
* @param treeNodeList
*/
private void findAndBindChild(TreeNode currentTreeNode, List<TreeNode> treeNodeList){
//再次循环查出的所有menu集合
for (TreeNode treeNode : treeNodeList) {
//判断循环节点的父节点id是否和当前节点的id相等,如果相等,说明当前循环节点是当前节点的孩子
if(currentTreeNode.getId()==treeNode.getParentId()){
//是孩子,就要添加到当前节点的孩子集合
//1,获取当前节点的孩子集合
List<TreeNode> children = currentTreeNode.getChildren();
//2,一定要判断孩子集合是否为空,如果是第一个孩子,孩子集合肯定为空,如果使用肯定空指针
if(children==null){
//3,如果为空,一定要实例化
children = new ArrayList<>();
}
// 4,根据上面判断,循环节点的父ID等于当前节点ID说明是孩子,加入
children.add(treeNode);
// 5,重新设置孩子集合
currentTreeNode.setChildren(children);
// 为了提高效率,每找到一个孩子,就从集合中删除,再次查找集合会变小,效率会变高 理论上可行,但是ArrayList不允许一边遍历一边删除元素
// treeNodeList.remove(treeNode);
//6,递归自己调用自己,再次判断当前循环有没有孩子,如果有执行相同操作
findAndBindChild(treeNode,treeNodeList);
}
}
}
/**
* 根据用户ID查询该用户对应的按钮权限集合
* @return
*/
@Override
public List<String> queryButtonPermsByUserId(String accessToken) {
//User user = (User)session.getAttribute("userInfo");
redisTemplate.setKeySerializer(new StringRedisSerializer());
User o = (User)redisTemplate.opsForValue().get(accessToken);
return menuDao.queryButtonPermsByUserId(o.getUserId());
}
/**
* 新增数据
*
* @param menu 实例对象
* @return 实例对象
*/
@Override
public Menu insert(Menu menu) {
DateTime date = DateUtil.date();
menu.setMenuName(menu.getLabel());
menu.setCreateTime(date);
menu.setUpdateTime(date);
this.menuDao.insert(menu);
return menu;
}
/**
* 修改数据
*
* @param menu 实例对象
* @return 实例对象
*/
@Override
public Menu update(Menu menu) {
DateTime date = DateUtil.date();
menu.setUpdateTime(date);
this.menuDao.update(menu);
return menu;
}
/**
* 通过主键删除数据
*
* @param menuId 主键
* @return 是否成功
*/
@Override
public boolean deleteById(Integer menuId) {
return this.menuDao.deleteById(menuId) > 0;
}
/**
* 添加角色权限关联方法
* @param roleId
* @param menuIds
* @return
*/
@Override
@Transactional
public int addRoleAndMenu(int roleId,String menuIds) {
//根据角色id删除该角色原来关联的所有权限
int sucNum1 = menuDao.deleteRoleMenuByRoleId(roleId);
int sucNum2 = 0;
//添加新的关联
if(!StrUtil.isEmpty(menuIds)){
String[] menuIdArray = menuIds.split(",");
//定义入参List
List<Map> mapList = new ArrayList<>();
Map map = null;
//循环拼装参数
for (String menuId : menuIdArray) {
map = new HashMap();
map.put("roleId",roleId);
map.put("menuId",menuId);
mapList.add(map);
}
//执行添加
sucNum2 = menuDao.addRoleAndMenu(mapList);
}
if(sucNum1>0&&sucNum2>0){
return 1;
}
return 0;
}
/**
* 根据角色ID查询该角色对应的权限ID集合
* @param roleId
* @return
*/
@Override
public List<Integer> queryMenuIdsByRoleId(int roleId) {
return menuDao.queryMenuIdsByRoleId(roleId);
}
}
<resultMap type="com.aaa.system.entity.Menu" id="MenuMap">
<result property="menuId" column="menu_id" jdbcType="INTEGER"/>
<result property="menuName" column="menu_name" jdbcType="VARCHAR"/>
<result property="parentId" column="parent_id" jdbcType="INTEGER"/>
<result property="orderNum" column="order_num" jdbcType="INTEGER"/>
<result property="url" column="url" jdbcType="VARCHAR"/>
<result property="menuType" column="menu_type" jdbcType="VARCHAR"/>
<result property="visible" column="visible" jdbcType="VARCHAR"/>
<result property="perms" column="perms" jdbcType="VARCHAR"/>
<result property="icon" column="icon" jdbcType="VARCHAR"/>
<result property="createBy" column="create_by" jdbcType="VARCHAR"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="updateBy" column="update_by" jdbcType="VARCHAR"/>
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
<result property="remark" column="remark" jdbcType="VARCHAR"/>
</resultMap>
<!-- 批量插入 -->
<insert id="insertBatch" keyProperty="menuId" useGeneratedKeys="true">
insert into qy142crms.sys_menu(menu_name, parent_id, order_num, url, menu_type, visible, perms, icon, create_by,
create_time, update_by, update_time, remark)
values
<foreach collection="entities" item="entity" separator=",">
(#{entity.menuName}, #{entity.parentId}, #{entity.orderNum}, #{entity.url}, #{entity.menuType},
#{entity.visible}, #{entity.perms}, #{entity.icon}, #{entity.createBy}, #{entity.createTime},
#{entity.updateBy}, #{entity.updateTime}, #{entity.remark})
</foreach>
</insert>
<!-- 批量插入或按主键更新 -->
<insert id="insertOrUpdateBatch" keyProperty="menuId" useGeneratedKeys="true">
insert into qy142crms.sys_menu(menu_name, parent_id, order_num, url, menu_type, visible, perms, icon, create_by,
create_time, update_by, update_time, remark)
values
<foreach collection="entities" item="entity" separator=",">
(#{entity.menuName}, #{entity.parentId}, #{entity.orderNum}, #{entity.url}, #{entity.menuType},
#{entity.visible}, #{entity.perms}, #{entity.icon}, #{entity.createBy}, #{entity.createTime},
#{entity.updateBy}, #{entity.updateTime}, #{entity.remark})
</foreach>
on duplicate key update
menu_name = values(menu_name) , parent_id = values(parent_id) , order_num = values(order_num) , url =
values(url) , menu_type = values(menu_type) , visible = values(visible) , perms = values(perms) , icon =
values(icon) , create_by = values(create_by) , create_time = values(create_time) , update_by = values(update_by)
, update_time = values(update_time) , remark = values(remark)
</insert>
<!--根据用户编号查询树形数据-->
<select id="queryTreeDataByUserId" resultType="com.aaa.common.entity.TreeNode">
select menu_id id,menu_name label,parent_id parentId,icon,url from sys_menu m where visible=0 and menu_type!='F'
and exists (
select 1 from sys_role_menu rm where rm.menu_id=m.menu_id
and exists(
select 1 from sys_user_role ur where ur.role_id=rm.role_id
and ur.user_id=#{userId}
)
)
</select>
<select id="queryAllTreeData" resultType="com.aaa.common.entity.TreeNode">
select menu_id id,menu_name label,parent_id parentId,icon,url,menu_type menuType,perms,visible,
ifnull((select menu_name from sys_menu m2 where m1.parent_id=m2.menu_id),'根节点') parentName
from sys_menu m1 where visible=0
</select>
<!--根据用户ID查询该用户对应的按钮权限集合-->
<select id="queryButtonPermsByUserId" resultType="string">
select perms from sys_menu m where visible=0 and menu_type='F'
and exists (
select 1 from sys_role_menu rm where rm.menu_id=m.menu_id
and exists(
select 1 from sys_user_role ur where ur.role_id=rm.role_id
and ur.user_id=#{userId}
)
)
</select>
<!--新增-->
<insert id="insert" keyProperty="menuId" useGeneratedKeys="true">
insert into sys_menu(menu_name, parent_id, order_num, url, menu_type, visible, perms, icon, create_by, create_time, update_by, update_time, remark)
values (#{menuName}, #{parentId}, #{orderNum}, #{url}, #{menuType}, #{visible}, #{perms}, #{icon}, #{createBy}, #{createTime}, #{updateBy}, #{updateTime}, #{remark})
</insert>
<!--通过主键修改数据-->
<update id="update">
update sys_menu
<set>
<if test="menuName != null and menuName != ''">
menu_name = #{menuName},
</if>
<if test="parentId != null">
parent_id = #{parentId},
</if>
<if test="orderNum != null">
order_num = #{orderNum},
</if>
<if test="url != null and url != ''">
url = #{url},
</if>
<if test="menuType != null and menuType != ''">
menu_type = #{menuType},
</if>
<if test="visible != null and visible != ''">
visible = #{visible},
</if>
<if test="perms != null and perms != ''">
perms = #{perms},
</if>
<if test="icon != null and icon != ''">
icon = #{icon},
</if>
<if test="createBy != null and createBy != ''">
create_by = #{createBy},
</if>
<if test="createTime != null">
create_time = #{createTime},
</if>
<if test="updateBy != null and updateBy != ''">
update_by = #{updateBy},
</if>
<if test="updateTime != null">
update_time = #{updateTime},
</if>
<if test="remark != null and remark != ''">
remark = #{remark},
</if>
</set>
where menu_id = #{menuId}
</update>
<!--通过主键删除-->
<delete id="deleteById">
delete from db_aiops03_crms.sys_menu where menu_id = #{menuId}
</delete>
<!--根据角色id删除该角色原来关联的所有权限-->
<delete id="deleteRoleMenuByRoleId">
delete from sys_role_menu where role_id=#{roleId}
</delete>
<!--添加角色权限关联方法-->
<insert id="addRoleAndMenu">
insert into sys_role_menu values
<foreach collection="list" item="map" separator=",">
(#{map.roleId},#{map.menuId})
</foreach>
</insert>
<!--根据角色ID查询该角色对应的权限ID集合-->
<select id="queryMenuIdsByRoleId" resultType="int">
select menu_id from sys_role_menu where role_id=#{roleId}
</select>
</mapper>
4.3角色服务实现类和sql语句
/**
* 角色信息表(Role)表服务实现类
*
* @author makejava
* @since 2022-03-14 16:52:39
*/
@Service("roleService")
public class RoleServiceImpl extends ServiceImpl<RoleDao, Role> implements RoleService {
@Resource
private RoleDao roleDao;
@Override
public List<Integer> queryRoleIdsByUserId(Integer userId) {
return roleDao.queryRoleIdsByUserId(userId);
}
@Transactional
@Override
public int addUserAndRole(int userId, String roleIds) {
//定义是否成功标识
boolean isSuc=true;
//删除以前该用户id关联的所有角色
int resultN = roleDao.deleteUserRoleByUserId(userId);
//判断是否为空 方法2执行
/*if(!StrUtil.isEmpty(roleIds)){
//不为空分割 5,6,7,8 roleIdArray=[5,6,7,8]
String[] roleIdArray = roleIds.split(",");
for (String roleId : roleIdArray) {
//循环添加
int resultNum = roleDao.addUserRole(userId, roleId);
if (resultNum<1){
isSuc=false;
}
}
}
if(isSuc&&resultN>0){
return 1;
}
*/
int sucNum = 0;
//方法1执行
if(!StrUtil.isEmpty(roleIds)){
List<Map> mapList = new ArrayList<>();
//不为空分割 5,6,7,8 roleIdArray=[5,6,7,8]
String[] roleIdArray = roleIds.split(",");
Map map = null;
for (String roleId : roleIdArray) {
map = new HashMap();
map.put("userId",userId);
map.put("roleId",roleId);
mapList.add(map);
}
sucNum = roleDao.addUserAndRole(mapList);
}
if(resultN>0&&sucNum>0){
return 1;
}
return 0;
}
/**
* 通过Map作为筛选条件分页查询
*
* @param map
* @return
*/
@Override
public PageInfo queryAll(Map map) {
if (map.get("pageNo") == null || map.get("pageSize") == null) {
throw new CustomException(ResultStatus.INVALID_ARGUMENT.getCode(),
ResultStatus.INVALID_ARGUMENT.getMessage());
}
Integer pageNo = Integer.valueOf(map.get("pageNo") + "");
Integer pageSize = Integer.valueOf(map.get("pageSize") + "");
//设值页码和每页显示数量
PageHelper.startPage(pageNo, pageSize);
//默认查询有效数据
if(map.get("isHaveSatus")!=null) {
map.put("status", "0");
}
//默认查询不被删除
map.put("delFlag","0");
//使用查询结果,构造PageInfo
PageInfo pageInfo = new PageInfo(this.roleDao.queryAll(map));
return pageInfo;
}
}
<mapper namespace="com.aaa.system.dao.RoleDao">
<resultMap type="com.aaa.system.entity.Role" id="RoleMap">
<result property="roleId" column="role_id" jdbcType="INTEGER"/>
<result property="roleName" column="role_name" jdbcType="VARCHAR"/>
<result property="roleKey" column="role_key" jdbcType="VARCHAR"/>
<result property="roleSort" column="role_sort" jdbcType="INTEGER"/>
<result property="dataScope" column="data_scope" jdbcType="VARCHAR"/>
<result property="status" column="status" jdbcType="VARCHAR"/>
<result property="delFlag" column="del_flag" jdbcType="VARCHAR"/>
<result property="createBy" column="create_by" jdbcType="VARCHAR"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="updateBy" column="update_by" jdbcType="VARCHAR"/>
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
<result property="remark" column="remark" jdbcType="VARCHAR"/>
</resultMap>
<!-- 批量插入 -->
<insert id="insertBatch" keyProperty="roleId" useGeneratedKeys="true">
insert into qy142crms.sys_role(role_name, role_key, role_sort, data_scope, status, del_flag, create_by,
create_time, update_by, update_time, remark)
values
<foreach collection="entities" item="entity" separator=",">
(#{entity.roleName}, #{entity.roleKey}, #{entity.roleSort}, #{entity.dataScope}, #{entity.status},
#{entity.delFlag}, #{entity.createBy}, #{entity.createTime}, #{entity.updateBy}, #{entity.updateTime},
#{entity.remark})
</foreach>
</insert>
<!-- 批量插入或按主键更新 -->
<insert id="insertOrUpdateBatch" keyProperty="roleId" useGeneratedKeys="true">
insert into qy142crms.sys_role(role_name, role_key, role_sort, data_scope, status, del_flag, create_by,
create_time, update_by, update_time, remark)
values
<foreach collection="entities" item="entity" separator=",">
(#{entity.roleName}, #{entity.roleKey}, #{entity.roleSort}, #{entity.dataScope}, #{entity.status},
#{entity.delFlag}, #{entity.createBy}, #{entity.createTime}, #{entity.updateBy}, #{entity.updateTime},
#{entity.remark})
</foreach>
on duplicate key update
role_name = values(role_name) , role_key = values(role_key) , role_sort = values(role_sort) , data_scope =
values(data_scope) , status = values(status) , del_flag = values(del_flag) , create_by = values(create_by) ,
create_time = values(create_time) , update_by = values(update_by) , update_time = values(update_time) , remark =
values(remark)
</insert>
<!-- 根据用户ID获取角色ID集合-->
<select id="queryRoleIdsByUserId" resultType="int">
select role_id from sys_user_role where user_id=#{userId}
</select>
<!--根据用户id删除该用户原来关联的所有角色-->
<delete id="deleteUserRoleByUserId">
delete from sys_user_role where user_id=#{userId}
</delete>
<!--添加用户角色关联方法1 (1,1),(1,2),(1,3)-->
<insert id="addUserAndRole">
insert into sys_user_role values
<foreach collection="list" item="map" separator=",">
(#{map.userId},#{map.roleId})
</foreach>
</insert>
<!--添加用户角色关联方法2-->
<insert id="addUserRole">
insert into sys_user_role values(#{userId},#{roleId})
</insert>
<!--查询单个-->
<select id="queryById" resultMap="RoleMap">
select
role_id, role_name, role_key, role_sort, data_scope, status, del_flag, create_by, create_time, update_by, update_time, remark
from db_aiops03_crms.sys_role
where role_id = #{roleId}
</select>
<!--通过实体作为筛选条件查询-->
<select id="queryAll" resultMap="RoleMap">
select
role_id, role_name, role_key, role_sort, data_scope, status, del_flag, create_by, create_time, update_by,
update_time, remark
from db_aiops03_crms.sys_role
<where>
<if test="roleId != null">
and role_id = #{roleId}
</if>
<if test="roleName != null and roleName != ''">
and role_name = #{roleName}
</if>
<if test="roleKey != null and roleKey != ''">
and role_key = #{roleKey}
</if>
<if test="roleSort != null">
and role_sort = #{roleSort}
</if>
<if test="dataScope != null and dataScope != ''">
and data_scope = #{dataScope}
</if>
<if test="status != null and status != ''">
and status = #{status}
</if>
<if test="delFlag != null and delFlag != ''">
and del_flag = #{delFlag}
</if>
<if test="createBy != null and createBy != ''">
and create_by = #{createBy}
</if>
<if test="createTime != null">
and create_time = #{createTime}
</if>
<if test="updateBy != null and updateBy != ''">
and update_by = #{updateBy}
</if>
<if test="updateTime != null">
and update_time = #{updateTime}
</if>
<if test="remark != null and remark != ''">
and remark = #{remark}
</if>
</where>
</select>
</mapper>
5.手机端服务
5.1验证码和登录的方法和sql和用到的工具类
/**
* (Member)表服务实现类
*
* @author makejava
* @since 2022-03-15 19:42:05
*/
@Service("memberService")
public class MemberServiceImpl extends ServiceImpl<MemberDao, Member> implements MemberService {
@Resource
private MemberDao memberDao;
@Resource
private RedisTemplate redisTemplate;
/* @Resource
private CouponHistoryService couponHistoryService;*/
/**
* 通过实体作为筛选条件查询
*
* @param pageNo 查询起始位置
* @param pageSize 查询条数
* @param member 实例对象
* @return 对象列表
*/
@Override
public Result queryAllByParam(int pageNo, int pageSize, Member member) {
if (pageNo == 0 || pageSize == 0){
throw new CustomException(ExceptionConstant.INVALID_ARGUMENT.getErrorCode(),
ExceptionConstant.INVALID_ARGUMENT.getErrorMessage());
}
PageHelper.startPage(pageNo,pageSize);
PageInfo<Member> pageInfo = new PageInfo<>(memberDao.queryAll(member));
return new Result(ReturnStatus.SUCCESS.getReturnCode(),
ReturnStatus.SUCCESS.getReturnMsg(), pageInfo);
}
@Override
public Result sentSM(String phoneNum) {
//生成验证码
String verifyCode = SMSUtil.createVerifyCode();
//发送验证码到手机
SMSUtil.sendSMS(phoneNum,verifyCode);
//把验证码存放起来,存放发送时间,用来验证是否过期 验证正确与否
// Session session = SessionUtil.getSession();
//把验证码存入第三方缓存,并设置过期时间
redisTemplate.opsForValue().set(phoneNum,verifyCode,
180, TimeUnit.SECONDS);
/* //写入注册方法中
long diffDate = DateUtil.date().getTime()-存放验证的时间;
if(diffDate/1000/60>10){
//提示验证码过期
}
if(session.getAttribute(phoneNum+"vc").equals(verifyCode)){
}*/
//session.setAttribute(phoneNum+"vc",verifyCode);
//session.setAttribute(phoneNum+"st", DateUtil.date());
return new Result(ResultStatus.SUCCESS.getCode(),
ResultStatus.SUCCESS.getMessage(),
verifyCode);
}
/**
* 新增数据
*
* @param member 实例对象
* @return 实例对象
*/
@Override
@Transactional
public Member insert(Member member) {
//验证验证码
//获取验证码
String code = member.getCode();
//从redis中获取存储的验证码
Object verifyCoide = redisTemplate.opsForValue().get(member.getPhoneNum());
if(verifyCoide==null||!verifyCoide.equals(code)){
throw new CustomException(ResultStatus.ERROR_VERIFY_CODE.getCode(),
ResultStatus.ERROR_VERIFY_CODE.getMessage());
}
//获取原始密码
String password = member.getPassword();
//随机盐值
String pwSalt = UUID.randomUUID().toString();
//计算密码
Sha512Hash sha512Hash = new Sha512Hash(password,pwSalt,
BusinessConstant.CredentialsMatcher.HASH_ITERATIONS);
member.setPassword(sha512Hash.toString());
member.setPwSalt(pwSalt);
member.setStatus(0);
member.setMemberLevelId(1);
member.setAccountBalance(0.0);
member.setIntegration(0);
member.setGrowth(0.0);
member.setHistoryIntegration("0");
this.memberDao.insert(member);
//优惠券历史表添加记录 注册送优惠券功能
//获取新增用户的ID
/* Integer id = member.getId();
CouponHistory couponHistory =new CouponHistory();
couponHistory.setCouponId(1l);
couponHistory.setMemberId(Long.valueOf(id));
couponHistory.setCouponCode("100001");
couponHistory.setGetType(0);
couponHistory.setCreateTime(DateUtil.date());
couponHistory.setUseStatus(1);
couponHistory.setUseTime(null);
couponHistory.setOrderId(null);
couponHistoryService.insert(couponHistory);*/
return member;
}
}
<mapper namespace="com.aaa.member.dao.MemberDao">
<resultMap type="com.aaa.member.entity.Member" id="MemberMap">
<result property="id" column="id" jdbcType="INTEGER"/>
<result property="username" column="username" jdbcType="VARCHAR"/>
<result property="password" column="password" jdbcType="VARCHAR"/>
<result property="pwSalt" column="pw_salt" jdbcType="VARCHAR"/>
<result property="status" column="status" jdbcType="INTEGER"/>
<result property="idType" column="id_type" jdbcType="VARCHAR"/>
<result property="pathFront" column="path_front" jdbcType="VARCHAR"/>
<result property="pathReverse" column="path_reverse" jdbcType="VARCHAR"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="contactName" column="contact_name" jdbcType="VARCHAR"/>
<result property="contactPhone" column="contact_phone" jdbcType="VARCHAR"/>
<result property="contactAddress" column="contact_address" jdbcType="VARCHAR"/>
<result property="licenseNo" column="license_no" jdbcType="VARCHAR"/>
<result property="sex" column="sex" jdbcType="VARCHAR"/>
<result property="phoneNum" column="phone_num" jdbcType="VARCHAR"/>
<result property="address" column="address" jdbcType="VARCHAR"/>
<result property="email" column="email" jdbcType="VARCHAR"/>
<result property="memberLevelId" column="member_level_id" jdbcType="INTEGER"/>
<result property="accountBalance" column="Account_Balance" jdbcType="NUMERIC"/>
<result property="integration" column="integration" jdbcType="INTEGER"/>
<result property="growth" column="growth" jdbcType="NUMERIC"/>
<result property="historyIntegration" column="history_integration" jdbcType="VARCHAR"/>
<result property="openId" column="open_id" jdbcType="INTEGER"/>
<result property="token" column="token" jdbcType="VARCHAR"/>
<result property="idCard" column="id_card" jdbcType="VARCHAR"/>
<result property="headPic" column="head_pic" jdbcType="VARCHAR"/>
</resultMap>
<!--新增所有列-->
<insert id="insert" keyProperty="id" useGeneratedKeys="true">
insert into mbs_member(username, password, pw_salt, status, id_type, path_front, path_reverse, name, contact_name, contact_phone, contact_address, license_no, sex, phone_num, address, email, member_level_id, Account_Balance, integration, growth, history_integration, open_id, token, id_card, head_pic)
values (#{username}, #{password}, #{pwSalt}, #{status}, #{idType}, #{pathFront}, #{pathReverse}, #{name}, #{contactName}, #{contactPhone}, #{contactAddress}, #{licenseNo}, #{sex}, #{phoneNum}, #{address}, #{email}, #{memberLevelId}, #{accountBalance}, #{integration}, #{growth}, #{historyIntegration}, #{openId}, #{token}, #{idCard}, #{headPic})
</insert>
<!-- 批量插入 -->
<insert id="insertBatch" keyProperty="id" useGeneratedKeys="true">
insert into qy142crms.mbs_member(username, password, pw_salt, status, id_type, path_front, path_reverse, name,
contact_name, contact_phone, contact_address, license_no, sex, phone_num, address, email, member_level_id,
Account_Balance, integration, growth, history_integration, open_id, token, id_card, head_pic)
values
<foreach collection="entities" item="entity" separator=",">
(#{entity.username}, #{entity.password}, #{entity.pwSalt}, #{entity.status}, #{entity.idType},
#{entity.pathFront}, #{entity.pathReverse}, #{entity.name}, #{entity.contactName}, #{entity.contactPhone},
#{entity.contactAddress}, #{entity.licenseNo}, #{entity.sex}, #{entity.phoneNum}, #{entity.address},
#{entity.email}, #{entity.memberLevelId}, #{entity.accountBalance}, #{entity.integration}, #{entity.growth},
#{entity.historyIntegration}, #{entity.openId}, #{entity.token}, #{entity.idCard}, #{entity.headPic})
</foreach>
</insert>
<!-- 批量插入或按主键更新 -->
<insert id="insertOrUpdateBatch" keyProperty="id" useGeneratedKeys="true">
insert into qy142crms.mbs_member(username, password, pw_salt, status, id_type, path_front, path_reverse, name,
contact_name, contact_phone, contact_address, license_no, sex, phone_num, address, email, member_level_id,
Account_Balance, integration, growth, history_integration, open_id, token, id_card, head_pic)
values
<foreach collection="entities" item="entity" separator=",">
(#{entity.username}, #{entity.password}, #{entity.pwSalt}, #{entity.status}, #{entity.idType},
#{entity.pathFront}, #{entity.pathReverse}, #{entity.name}, #{entity.contactName}, #{entity.contactPhone},
#{entity.contactAddress}, #{entity.licenseNo}, #{entity.sex}, #{entity.phoneNum}, #{entity.address},
#{entity.email}, #{entity.memberLevelId}, #{entity.accountBalance}, #{entity.integration}, #{entity.growth},
#{entity.historyIntegration}, #{entity.openId}, #{entity.token}, #{entity.idCard}, #{entity.headPic})
</foreach>
on duplicate key update
username = values(username) , password = values(password) , pw_salt = values(pw_salt) , status = values(status)
, id_type = values(id_type) , path_front = values(path_front) , path_reverse = values(path_reverse) , name =
values(name) , contact_name = values(contact_name) , contact_phone = values(contact_phone) , contact_address =
values(contact_address) , license_no = values(license_no) , sex = values(sex) , phone_num = values(phone_num) ,
address = values(address) , email = values(email) , member_level_id = values(member_level_id) , Account_Balance
= values(Account_Balance) , integration = values(integration) , growth = values(growth) , history_integration =
values(history_integration) , open_id = values(open_id) , token = values(token) , id_card = values(id_card) ,
head_pic = values(head_pic)
</insert>
<!--通过实体作为筛选条件查询-->
<select id="queryAll" resultMap="MemberMap">
select
a.id, a.username, password, pw_salt, status, id_type, path_front, path_reverse, a.name, contact_name, contact_phone,
contact_address, license_no, sex, phone_num, address, email, member_level_id, Account_Balance, integration,
growth, history_integration, open_id, token, head_pic,b.name levelName from
mbs_member a left join mbs_member_level b on
a.member_level_id=b.id
<where>
<if test="id != null">
and id = #{id}
</if>
<if test="username != null and username != ''">
and a.username like '%' #{username} '%'
</if>
<if test="password != null and password != ''">
and password = #{password}
</if>
<if test="pwSalt != null and pwSalt != ''">
and pw_salt = #{pwSalt}
</if>
<if test="status != null">
and status = #{status}
</if>
<if test="idType != null and idType != ''">
and id_type = #{idType}
</if>
<if test="pathFront != null and pathFront != ''">
and path_front = #{pathFront}
</if>
<if test="pathReverse != null and pathReverse != ''">
and path_reverse = #{pathReverse}
</if>
<if test="name != null and name != ''">
and a.name like '%' #{name} '%'
</if>
<if test="contactName != null and contactName != ''">
and contact_name = #{contactName}
</if>
<if test="contactPhone != null and contactPhone != ''">
and contact_phone = #{contactPhone}
</if>
<if test="contactAddress != null and contactAddress != ''">
and contact_address = #{contactAddress}
</if>
<if test="licenseNo != null and licenseNo != ''">
and license_no = #{licenseNo}
</if>
<if test="sex != null and sex != ''">
and sex = #{sex}
</if>
<if test="phoneNum != null and phoneNum != ''">
and phone_num = #{phoneNum}
</if>
<if test="address != null and address != ''">
and address = #{address}
</if>
<if test="email != null and email != ''">
and email = #{email}
</if>
<if test="memberLevelId != null">
and member_level_id = #{memberLevelId}
</if>
<if test="accountBalance != null">
and Account_Balance = #{accountBalance}
</if>
<if test="integration != null">
and integration = #{integration}
</if>
<if test="growth != null and growth != 0 ">
and growth = #{growth}
</if>
<if test="historyIntegration != null and historyIntegration != ''">
and history_integration = #{historyIntegration}
</if>
<if test="openId != null">
and open_id = #{openId}
</if>
<if test="token != null and token != ''">
and token = #{token}
</if>
<if test="headPic != null and headPic != ''">
and head_pic = #{headPic}
</if>
</where>
</select>
</mapper>
/**
* @ fileName:SMSUtil
* @ description:
* @ author:zhz
* @ createTime:2021/7/29 15:22
* @ version:1.0.0
*/
public class SMSUtil {
/**
* 发送验证码
* @param phoneNumbers 电话号码
* @param verifyCode 验证码
* @return
*/
/* public static String sendSMS(String phoneNumbers,String verifyCode){
try {
//设置超时时间-可自行调整
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//初始化ascClient需要的几个参数
final String product = "Dysmsapi";//短信API产品名称(短信产品名固定,无需修改)
final String domain = "dysmsapi.aliyuncs.com";//短信API产品域名(接口地址固定,无需修改)
//替换成你的AK
final String accessKeyId = "LTAI4GEH3ciDi5SVsvFVi6H2";//你的accessKeyId,参考本文档步骤2
final String accessKeySecret = "l0I6MhbsKPGH1tLmVE25L5naKKO79C";//你的accessKeySecret,参考本文档步骤2
//初始化ascClient,暂时不支持多region(请勿修改)
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId,
accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
//组装请求对象
SendSmsRequest request = new SendSmsRequest();
//使用post提交
request.setMethod(MethodType.POST);
//必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式;发送国际/港澳台消息时,接收号码格式为国际区号+号码,如“85200000000”
request.setPhoneNumbers(phoneNumbers);
//必填:短信签名-可在短信控制台中找到
request.setSignName(BusinessConstant.Sms.SIGNNAME);
//必填:短信模板-可在短信控制台中找到,发送国际/港澳台消息时,请使用国际/港澳台短信模版
request.setTemplateCode(BusinessConstant.Sms.TEMPLATE_CODE);
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
//友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败
//参考:request.setTemplateParam("{\"变量1\":\"值1\",\"变量2\":\"值2\",\"变量3\":\"值3\"}")
request.setTemplateParam("{\"code\":\""+verifyCode+"\"}");
//可选-上行短信扩展码(扩展码字段控制在7位或以下,无特殊需求用户请忽略此字段)
//request.setSmsUpExtendCode("90997");
//可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
request.setOutId("yourOutId");
//请求失败这里会抛ClientException异常
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
if(sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) {
return "suc";
}
} catch (Exception e) {
e.printStackTrace();
}
return "error";
}*/
/**
* 使用AK&SK初始化账号Client
*
* @param accessKeyId
* @param accessKeySecret
* @return Client
* @throws Exception
*/
public static com.aliyun.dysmsapi20170525.Client createClient(String accessKeyId, String accessKeySecret) throws Exception {
Config config = new Config()
// 您的AccessKey ID
.setAccessKeyId(accessKeyId)
// 您的AccessKey Secret
.setAccessKeySecret(accessKeySecret);
// 访问的域名
config.endpoint = "dysmsapi.aliyuncs.com";
return new com.aliyun.dysmsapi20170525.Client(config);
}
/**
* 新版本的发送接口
*
* @param phoneNumbers
* @param verifyCode
* @return
*/
public static String sendSMS(String phoneNumbers, String verifyCode) {
try {
// java.util.List<String> args = java.util.Arrays.asList(args_);
/* final String accessKeyId = "LTAI4GEH3ciDi5SVsvFVi6H2";//你的accessKeyId,参考本文档步骤2
final String accessKeySecret = "l0I6MhbsKPGH1tLmVE25L5naKKO79C";//你的accessKeySecret,参考本文档步骤2*/
com.aliyun.dysmsapi20170525.Client client = SMSUtil.createClient("LTAI4GEH3ciDi5SVsvFVi6H2", "l0I6MhbsKPGH1tLmVE25L5naKKO79C");
SendSmsRequest request = new SendSmsRequest();
//使用post提交
//request.setMethod(MethodType.POST);
//必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式;发送国际/港澳台消息时,接收号码格式为国际区号+号码,如“85200000000”
request.setPhoneNumbers(phoneNumbers);
//必填:短信签名-可在短信控制台中找到
request.setSignName(BusinessConstant.Sms.SIGNNAME);
//必填:短信模板-可在短信控制台中找到,发送国际/港澳台消息时,请使用国际/港澳台短信模版
request.setTemplateCode(BusinessConstant.Sms.TEMPLATE_CODE);
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
//友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败
//参考:request.setTemplateParam("{\"变量1\":\"值1\",\"变量2\":\"值2\",\"变量3\":\"值3\"}")
request.setTemplateParam("{\"code\":\"" + verifyCode + "\"}");
//可选-上行短信扩展码(扩展码字段控制在7位或以下,无特殊需求用户请忽略此字段)
//request.setSmsUpExtendCode("90997");
//可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
request.setOutId("yourOutId");
// 复制代码运行请自行打印 API 的返回值
SendSmsResponse sendSmsResponse = client.sendSms(request);
if (sendSmsResponse.getBody().getCode() != null && sendSmsResponse.getBody().getCode().endsWith("OK")) {
return "suc";
}
} catch (Exception e) {
e.printStackTrace();
}
return "error";
}
/**
* 生成验证码
*
* @return
*/
public static String createVerifyCode() {
Random random = new Random();
return String.valueOf(random.nextInt(900000) + 100000);
}
public static void main(String[] args) {
String s = SMSUtil.sendSMS("17508926376", createVerifyCode());
System.out.println(s+"++");
if("suc".equals(s)){
System.out.println("成功!");
}
}
}
5.2aop操作日志,作用与整个服务器,远程调用新增日志
package com.aaa.member.util;
import com.aaa.common.bo.OperLog;
import com.aaa.common.bo.User;
import com.aaa.common.constant.BusinessConstant;
import com.aaa.member.service.OperLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;
/**
* fileName:OperationLogUtil
* description:切面功能的实现类,操作日志记录类 通知或增强
* author: znb
* createTime:2020/12/3 0003 08:53
* version:1.0.0
*/
@Component
@Aspect //通知或增强类 注释
@SuppressWarnings("all")
public class OperationLogUtil {
@Autowired
private OperLogService operLogService;
@Autowired
private HttpSession session;
// @Pointcut(value = "execution()")
// private void pointCut(){}
/**
* 操作日志记录功能
* @param joinPoint
*/
@AfterReturning(pointcut = "execution(* com.aaa.member.controller.*.insert*(..))" +
"||execution(* com.aaa.member.controller.*.update*(..))" +
"||execution(* com.aaa.member.controller.*.delete*(..))")
public void recordOperLog(JoinPoint joinPoint){
OperLog operLog = new OperLog();
operLog.setTitle("会员管理模块");
//获取连接点的方法名称
String methodName = joinPoint.getSignature().getName();
//定义业务类型变量
int businessType = 0;
if (methodName.contains("insert")){
businessType = BusinessConstant.OperationLogType.INSERT;
}else if (methodName.contains("update")){
businessType = BusinessConstant.OperationLogType.UPDATE;
}else {
businessType = BusinessConstant.OperationLogType.DELETE;
}
//设置日志业务操作类型
operLog.setBusinessType(businessType);
//获取目标对象的名称
String targetName = joinPoint.getTarget().getClass().getName();
//操作方法名称
operLog.setMethod(targetName+"."+methodName);
operLog.setOperatorType(BusinessConstant.OperLogCustomerType.BACKUSER);
User user = (User)session.getAttribute("userInfo");
if (user!=null){
operLog.setOperName(user.getLoginName());
operLog.setDeptName(user.getDeptId()+"");
}
//获取Request对象
ServletRequestAttributes requestAttributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
//获取IP地址
String remoteAddr = request.getRemoteAddr();
operLog.setOperIp(remoteAddr);
operLog.setOperUrl(request.getRequestURI());
//根据获取到的IP地址,调用远程接口,判断IP归属地,如果获取不到,说明是内网IP
operLog.setOperLocation("内网IP");
//获取连接点的参数
Object[] args = joinPoint.getArgs();
if (args!=null&&args.length>0){
String simpleName = args[0].getClass().getSimpleName();
operLog.setOperParam(simpleName);
}
operLog.setStatus(0);
operLog.setErrorMsg("异常类名称");
operLog.setOperTime(new Date());
//执行添加操作
operLogService.insert(operLog);
}
}
/**
* 操作日志记录(OperLog)表服务接口
*
* @author makejava
* @since 2020-12-03 08:39:00
*/
@FeignClient("SystemServer")
public interface OperLogService {
/**
* 远程调用服务contentService中 新增数据
*
* @param operLog 实例对象
* @return 实例对象
*/
@PostMapping("/operLog/insert")
OperLog insert(@RequestBody OperLog operLog);
}
5.3mybatis-pulas分页插件
/**
* @ fileName:MybatisPlusConfig
* @ description:
* @ author:葛爷独创代码
* @ createTime:2022/3/16 17:20
* @ version:1.0.0
*/
@Configuration
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}