src/main/java/com/whyc/controller/FaceController.java
@@ -1,12 +1,36 @@ package com.whyc.controller; import com.arcsoft.face.FaceEngine; import com.arcsoft.face.toolkit.ImageFactory; import com.arcsoft.face.toolkit.ImageInfo; import com.google.gson.reflect.TypeToken; import com.whyc.constant.YamlProperties; import com.whyc.dto.Response; import com.whyc.factory.FaceEngineFactory; import com.whyc.pojo.PermitGroup; import com.whyc.pojo.UserFace; import com.whyc.pojo.UserInf; import com.whyc.service.FaceService; import com.whyc.service.PermitGroupUserService; import com.whyc.service.UserService; import com.whyc.util.ActionUtil; import com.whyc.util.FaceIdentifyUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.assertj.core.util.Arrays; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import sun.misc.BASE64Decoder; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.List; import static com.whyc.util.ActionUtil.getApplication; /** * 人脸识别 @@ -16,13 +40,306 @@ @Api(tags = "人脸识别") public class FaceController { @Resource private FaceService service; @Resource private PermitGroupUserService permitGroupUserService; @Resource private UserService userService; @GetMapping("activeOnline") @ApiOperation(value = "在线激活人脸识别引擎",notes = "只需要刚开始时调用一次,会导致appId与硬件设备绑定,必须有外部网络,否则激活会失败!" + "后续使用无需再调用激活,可以离线使用") public Response activeOnline(){ return null; Response model = new Response(); boolean b = FaceIdentifyUtil.activeOnline(); if(b){ return new Response().set(1,true,"引擎激活成功"); }else{ return new Response().set(1,false,"引擎激活失败,请检查网络是否为外网并确认appId和key是否正确!"); } } @PostMapping @ApiOperation(value = "添加,加入到人脸库") public Response add(@RequestParam String fileData,String uName,Integer uId ){ //传参 uId,uName,fileData--文件流 fileData = fileData.replaceAll(" ", "+"); //由于图片字符串是由base64编码的,解码成字节数组 //data:image/jpeg;base64, // fileData = fileData.replaceAll("data:image/jpeg;base64,",""); fileData = fileData.split(",")[1]; BASE64Decoder decoder = new BASE64Decoder(); byte[] dataBytes = new byte[0]; try { dataBytes = decoder.decodeBuffer(fileData); /*for (int i = 0; i < dataBytes.length; ++i) { if (dataBytes[i] < 0) {// 调整异常数据 dataBytes[i] += 256; } }*/ } catch (IOException e) { e.printStackTrace(); } /*=========检查图片是否有效=======*/ //检验图片是否有效 ImageInfo imageInfo = ImageFactory.getRGBData(dataBytes); //初始化引擎 // FaceEngine faceEngine = FaceIdentifyUtil.init(); FaceEngine faceEngine = FaceEngineFactory.getInstance(); if (faceEngine==null){ return new Response().set(1,false,"初始化引擎失败"); }else { //检查角度是否端正,检查人脸像素大小是否>50×50 Response checkRes1 = FaceIdentifyUtil.orientAndPxDetect(faceEngine,imageInfo); if((boolean)checkRes1.getData()){ /*=========图片保存===========*/ //获取到tomcat webapp绝对路径 String realPath = getApplication().getRealPath("/"); // String[] split = realPath.split(File.separator); String[] split = realPath.split("\\\\"); String projectName = split[split.length - 1]; String webAppPath = realPath.substring(0, realPath.lastIndexOf(projectName)); //存储人脸图片的文件夹 String fileDirName = webAppPath + projectName + "_photo"; File file = new File(fileDirName); //不存在则创建该文件夹 if (!file.exists()) { file.mkdirs(); } //文件全路径 String fileName = fileDirName + File.separator + uName + ".jpg"; try { FileOutputStream fot = new FileOutputStream(fileName); fot.write(dataBytes); fot.flush(); fot.close(); } catch (IOException e) { e.printStackTrace(); } /*=========数据库表更新===========*/ // model = service.add(uId, uName, projectName); service.add(uId, uName, fileName); return new Response().set(1,true,"新增成功"); } return checkRes1; } } /** * 人脸库管理: 更新 * @return */ @PutMapping @ApiOperation(value = "更新") public Response update(@RequestParam String fileData,String uName){ //传参,uName,fileData--文件流 //由于图片字符串是由base64编码的,解码成字节数组 fileData = fileData.replaceAll(" ", "+"); fileData = fileData.split(",")[1]; BASE64Decoder decoder = new BASE64Decoder(); byte[] dataBytes = new byte[0]; try { dataBytes = decoder.decodeBuffer(fileData); } catch (IOException e) { e.printStackTrace(); } /*=========检查图片是否有效=======*/ //检验图片是否有效 //获取图像信息 ImageInfo imageInfo = ImageFactory.getRGBData(dataBytes); //初始化引擎 // FaceEngine faceEngine = FaceIdentifyUtil.init(); FaceEngine faceEngine = FaceEngineFactory.getInstance(); if (faceEngine==null){ return new Response().set(1,false,"初始化引擎失败"); }else { //检测图片 Response checkRes1 = FaceIdentifyUtil.orientAndPxDetect(faceEngine, imageInfo); if ((boolean)checkRes1.getData()) { /*=========图片保存===========*/ //获取到tomcat webapp绝对路径 String realPath = getApplication().getRealPath("/"); String[] split = realPath.split(File.separator); String projectName = split[split.length - 1]; String webAppPath = realPath.substring(0, realPath.lastIndexOf(projectName)); //存储人脸图片的文件夹 String fileDirName = webAppPath + projectName + "_photo"; File file = new File(fileDirName); //不存在则创建该文件夹 if (!file.exists()) { file.mkdirs(); } //文件全路径 String fileName = fileDirName + File.separator + uName + ".jpg"; try { FileOutputStream fot = new FileOutputStream(fileName); fot.write(dataBytes); fot.flush(); fot.close(); } catch (IOException e) { e.printStackTrace(); } return new Response().setII(1,"更新成功"); } return checkRes1; } } /** * 人脸库管理: 删除 * @return */ @DeleteMapping @ApiOperation(value = "删除") @Transactional public Response delete(@RequestParam Integer uId,@RequestParam Integer faceId, @RequestParam String uName){ //更新user_inf和face表 service.update(uId,faceId); //删除图片 //获取到图片所在文件夹的全路径 String fileName = findFileDirPath(); //获取图片的全路径 File file = new File(fileName+File.separator+uName+".jpg"); if(file.exists()){ file.delete(); } return new Response().setII(1,"删除成功"); } /**获取图片文件夹全路径*/ private String findFileDirPath() { String realPath = getApplication().getRealPath("/"); String[] split = realPath.split("\\\\"); String projectName = split[split.length - 1]; String webAppPath = realPath.substring(0, realPath.lastIndexOf(projectName)); //存储人脸图片的文件夹 String fileDirName = webAppPath + "\\" + projectName + "_photo"; return fileDirName; } /**获取图片的http加载url*/ private String findWebPhotoUrl(String uName){ HttpServletRequest request = ActionUtil.getRequest(); //获取项目名称 String realPath = ActionUtil.getApplication().getRealPath("/"); String[] split = realPath.split("/"); String projectName = split[split.length - 1]; //图片保存路径,采取ip+port访问形式而非硬盘形式,方便图片加载 String url = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+"/"+projectName+"_photo/"+uName+".jpg"; return url; } /** * 人脸库管理: 查询分页列表 * 现在逻辑是当前用户查询自己的人脸信息 * @return */ @GetMapping("info") @ApiOperation(value = "查询人脸信息") public Response getInfo(){ //传入pageNum,pageSize UserInf userInf = (UserInf) ActionUtil.getSession().getAttribute("user"); UserInf user = service.getInfo(userInf.getUId()); return new Response().set(1,user); } /** * 人脸识别: 活体检验,相似度对比,1比N */ @PostMapping("faceCompare2N") @ApiOperation(value = "人脸识别对比") public Response faceCompare2N(@RequestParam String fileData){ Response res = new Response(); /*====获取图片并校验活体,角度,像素大小====*/ //由于图片字符串是由base64编码的,解码成字节数组 fileData = fileData.replaceAll(" ", "+"); fileData = fileData.split(",")[1]; BASE64Decoder decoder = new BASE64Decoder(); byte[] dataBytes = new byte[0]; try { dataBytes = decoder.decodeBuffer(fileData); } catch (IOException e) { e.printStackTrace(); } ImageInfo imageInfo = ImageFactory.getRGBData(dataBytes); FaceEngine faceEngine = FaceEngineFactory.getInstance(); if(faceEngine!=null) { res = FaceIdentifyUtil.liveDetect(faceEngine, imageInfo); //活体校验通过 if (res.getCode() == 1) { res = FaceIdentifyUtil.orientAndPxDetect(faceEngine, imageInfo); //人像角度,大小校验通过 if(res.getCode()==1) { //获取数据库中所有的人脸图片 List<UserInf> userInfList = service.findAllFaceUrl(); if(userInfList.size()==0){ res.setCode(0); res.setMsg("人脸库暂无任何数据"); }else{ for (UserInf temp:userInfList){ String filePath = temp.getFace().getUrl(); ImageInfo imageInfo2 = ImageFactory.getRGBData(new File(filePath)); Response res3 = FaceIdentifyUtil.faceCompare(faceEngine, imageInfo, imageInfo2); //对比成功,记录用户登录信息 if(res3.getCode()==1){ // 将登陆成功的用户存入session ActionUtil.getSession().setAttribute("user", temp); //设置session不活动时间为30分 ActionUtil.getSession().setMaxInactiveInterval(60 * 30); ActionUtil.getSession().setAttribute("ip", ActionUtil.getRequest().getRemoteAddr()); List<PermitGroup> permitList = permitGroupUserService.getPermitByUser(temp.getUId()); if (permitList!=null && permitList.size()!=0) { ActionUtil.getSession().setAttribute("permits", permitList); } else { res.setCode(0); res.setMsg("还未分配权限"); } //将新登录的用户存入application userService.setApplication(temp); } } } } } }else{ res.setCode(0); res.setMsg("初始化引擎失败"); } return res; } } src/main/java/com/whyc/dto/Response.java
@@ -46,6 +46,12 @@ return this; } public Response<T> setII(Integer code,String msg) { this.code = code; this.msg = msg; return this; } public Integer getCode() { return code; } src/main/java/com/whyc/factory/FaceEngineFactory.java
New file @@ -0,0 +1,16 @@ package com.whyc.factory; import com.arcsoft.face.FaceEngine; import com.whyc.util.FaceIdentifyUtil; /** * 单例工厂,获取FaceEngine: * 采取恶汉模式 */ public class FaceEngineFactory { private static FaceEngine faceEngine = FaceIdentifyUtil.init(); public static FaceEngine getInstance(){ return faceEngine; } } src/main/java/com/whyc/mapper/FaceMapper.java
New file @@ -0,0 +1,14 @@ package com.whyc.mapper; import com.whyc.pojo.UserFace; import com.whyc.pojo.UserInf; import java.util.List; public interface FaceMapper extends CustomMapper<UserFace> { UserInf getInfo(Long uId); List<UserInf> findAllFaceUrl(); } src/main/java/com/whyc/mapper/PermitGroupUserMapper.java
New file @@ -0,0 +1,10 @@ package com.whyc.mapper; import com.whyc.pojo.PermitGroup; import com.whyc.pojo.PermitGroupUser; import java.util.List; public interface PermitGroupUserMapper extends CustomMapper<PermitGroupUser> { List<PermitGroup> getPermitByUser(Long userId); } src/main/java/com/whyc/pojo/PermitGroup.java
New file @@ -0,0 +1,64 @@ package com.whyc.pojo; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import org.apache.ibatis.type.Alias; /** * 权限组 */ @Alias("PermitGroup") @TableName(value = "tb_user_permitgroup") public class PermitGroup { @TableId private Long num; @TableField private Integer permitGroupId; @TableField private String permitGroupName; @TableField private String permitItemName; @TableField private String permitItemValue; public Long getNum() { return num; } public void setNum(Long num) { this.num = num; } public Integer getPermitGroupId() { return permitGroupId; } public void setPermitGroupId(Integer permitGroupId) { this.permitGroupId = permitGroupId; } public String getPermitGroupName() { return permitGroupName; } public void setPermitGroupName(String permitGroupName) { this.permitGroupName = permitGroupName; } public String getPermitItemName() { return permitItemName; } public void setPermitItemName(String permitItemName) { this.permitItemName = permitItemName; } public String getPermitItemValue() { return permitItemValue; } public void setPermitItemValue(String permitItemValue) { this.permitItemValue = permitItemValue; } } src/main/java/com/whyc/pojo/PermitGroupUser.java
New file @@ -0,0 +1,44 @@ package com.whyc.pojo; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import org.apache.ibatis.type.Alias; /** * 用户权限组 */ @Alias("PermitGroupUser") @TableName(value = "tb_user_permitgroup_data") public class PermitGroupUser { @TableId private Integer num; @TableField private Integer permitGroupId; @TableField private Integer uId; public Integer getNum() { return num; } public void setNum(Integer num) { this.num = num; } public Integer getPermitGroupId() { return permitGroupId; } public void setPermitGroupId(Integer permitGroupId) { this.permitGroupId = permitGroupId; } public Integer getuId() { return uId; } public void setuId(Integer uId) { this.uId = uId; } } src/main/java/com/whyc/pojo/UserClient.java
New file @@ -0,0 +1,51 @@ package com.whyc.pojo; public class UserClient { /**客户端ip地址 */ public String ip; /** 客户端用户信息*/ public UserInf user; /** 客户端登录时间的毫秒数*/ public Long login_times; public UserClient() { } public UserClient(String ip, UserInf user) { super(); this.ip = ip; this.user = user; } public UserClient(String ip, UserInf user, Long login_times) { super(); this.ip = ip; this.user = user; this.login_times = login_times; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public UserInf getUser() { return user; } public void setUser(UserInf user) { this.user = user; } public Long getLogin_times() { return login_times; } public void setLogin_times(Long login_times) { this.login_times = login_times; } } src/main/java/com/whyc/pojo/UserFace.java
@@ -15,6 +15,18 @@ /**人脸图片路径,http*/ private String url; public UserFace() { } public UserFace(String url) { this.url = url; } public UserFace(Integer id, String url) { this.id = id; this.url = url; } public Integer getId() { return id; } src/main/java/com/whyc/pojo/UserInf.java
@@ -8,22 +8,20 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; import org.apache.ibatis.type.Alias; import java.io.Serializable; import java.util.Date; /** * <p> * * </p> * * @author lxw * @since 2021-10-14 */ @Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @ApiModel(value="TbUserInf对象", description="") @ApiModel(value="TbUserInf对象") @Alias("UserInf") public class UserInf implements Serializable { private static final long serialVersionUID = 1L; @@ -99,7 +97,8 @@ @TableField("uKey_ID") private String ukeyId; private Integer faceId; @TableField("face_id") private UserFace face; private String license; src/main/java/com/whyc/service/FaceService.java
New file @@ -0,0 +1,76 @@ package com.whyc.service; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.github.pagehelper.PageInfo; import com.whyc.mapper.FaceMapper; import com.whyc.mapper.UserMapper; import com.whyc.pojo.UserFace; import com.whyc.pojo.UserInf; import org.apache.catalina.User; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.List; @Service public class FaceService { @Resource private FaceMapper mapper; @Resource private UserMapper userMapper; /** * 两种分页:mybatis-plus自带和PageHelper的自定义 * @param page * @param uId * @return */ /*public List<UserFace> getPage(PageInfo page, int uId) { PageInfo<Face> pageInfo = mapper.findAll(page,uId); model.setCode(1); model.setData(pageInfo); return model; }*/ /**TODO 待错误测试*/ @Transactional public boolean add(int uId, String uName, String fileName) { //人脸表新增记录 UserFace userFace = new UserFace(uName); mapper.insert(userFace); //用户表关联新增的人脸表记录id UpdateWrapper<UserInf> wrapper = Wrappers.update(); wrapper.set("face_id",userFace.getId()).eq("uId",uId); userMapper.update(null,wrapper); return true; } /**TODO 待错误测试*/ /**逻辑删除,取消用户与图片的关系*/ public boolean update(int uId,int faceId) { //人脸表删除记录 mapper.deleteById(faceId); //用户表关联新增的人脸表记录id UpdateWrapper<UserInf> wrapper = Wrappers.update(); wrapper.set("face_id",null).eq("uId",uId); userMapper.update(null,wrapper); return true; } public UserInf getInfo(Long uId) { return mapper.getInfo(uId); } public List<UserInf> findAllFaceUrl() { return mapper.findAllFaceUrl(); } } src/main/java/com/whyc/service/LoginService.java
@@ -27,9 +27,10 @@ } if (subject.isAuthenticated()){ //每个登录的用户都有一个全局变量,里面存着对应的SessionId; //同一个账号,后面登录的,会挤掉之前登录的SessionId System.out.println("全局存储中当前SessionId为:"+request.getSession().getId()); //同一个账号,后面登录的,会挤掉之前登录的SessionId,这个todo,做限制账号同时登陆人数为1 request.getServletContext().setAttribute(userName,request.getSession().getId()); //Session存储当前用户 request.getSession().setAttribute("user",subject.getPrincipal()); return new Response<>().set(1,true,"登录成功"); } return new Response<>().set(1,false,"密码错误"); src/main/java/com/whyc/service/PermitGroupUserService.java
New file @@ -0,0 +1,20 @@ package com.whyc.service; import com.whyc.mapper.PermitGroupUserMapper; import com.whyc.pojo.PermitGroup; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; @Service public class PermitGroupUserService { @Resource private PermitGroupUserMapper mapper; public List<PermitGroup> getPermitByUser(Long userId){ return mapper.getPermitByUser(userId); } } src/main/java/com/whyc/service/UserBridgeService.java
@@ -31,7 +31,7 @@ public UserInf findPasswordByUserName(String userName) { UserInf userInf = null; QueryWrapper<UserInf> queryWrapper = Wrappers.query(); queryWrapper.select("uId","uName","upassword").eq("uName",userName); queryWrapper.select("uId","uName","uSnId","upassword","UKey_ID","uRole").eq("uName",userName); userInf = userMapper.selectOne(queryWrapper); return userInf==null?new UserInf(0L,"用户不存在"):userInf; src/main/java/com/whyc/service/UserService.java
@@ -4,14 +4,20 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.whyc.dto.Response; import com.whyc.mapper.UserMapper; import com.whyc.pojo.UserClient; import com.whyc.pojo.UserInf; import com.whyc.util.ActionUtil; import com.whyc.util.DigestsUtil; import lombok.extern.slf4j.Slf4j; import org.apache.catalina.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; import javax.annotation.Resource; import javax.servlet.ServletContext; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -69,4 +75,23 @@ return userMapper.deleteById(id)>0; } // 将所有登陆的用户的信息存到application中 public void setApplication(UserInf user) { ServletContext application = ActionUtil.getApplication(); //查看全局中存储的users的Map的key-value集合 Map<String, UserClient> map = (Map) application.getAttribute("users"); if (map == null) { map = new HashMap<String, UserClient>(); } else { //如果集合中有值,则获取当前用户对应的用户信息,key为用户名username,Value为用户名,存储的时间 UserClient client = map.get(user.getUName()); if (client != null) { //已存在 map.remove(user.getUName()); } } Long login_time = new Date().getTime(); ActionUtil.getSession().setAttribute("login_time", login_time); map.put(user.getUName(), new UserClient(ActionUtil.getRequest().getRemoteAddr(),user,login_time)); application.setAttribute("users", map); } } src/main/java/com/whyc/util/FaceIdentifyUtil.java
@@ -110,26 +110,21 @@ } public static Response orientAndPxDetect(FaceEngine faceEngine, ImageInfo imageInfo) { Response response = new Response(); response.setCode(1); //检查角度是否端正,检查人脸像素大小是否>50×50 List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>(); faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList); if (faceInfoList.size()<1){ response.setCode(0); response.setMsg("无效的人脸信息"); return new Response().set(1,false,"无效的人脸信息"); }else { FaceInfo faceInfo = faceInfoList.get(0); Rect rect = faceInfo.getRect(); if (faceInfo.getOrient() != 1) { response.setCode(0); response.setMsg("人像姿势不端正"); return new Response().set(1,false,"人像姿势不端正"); } else if ((rect.bottom - rect.top) < 50 || (rect.right - rect.left) < 50) { response.setCode(0); response.setMsg("人像面部像素太低"); return new Response().set(1,false,"人像面部像素太低"); } } return response; return new Response().set(1,true,"校验通过"); } public static Response liveDetect(FaceEngine faceEngine, ImageInfo imageInfo) { src/main/resources/mapper/FaceMapper.xml
New file @@ -0,0 +1,35 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.whyc.mapper.FaceMapper" > <resultMap id="Map_UserInf" type="UserInf"> <id property="uId" column="uId" /> <result property="uName" column="uName"/> <association property="face" javaType="UserFace"> <id property="id" column="faceId" jdbcType="INTEGER"/> <result property="url" column="faceUrl" jdbcType="VARCHAR"/> </association> </resultMap> <resultMap id="Map_UserInf2" type="UserInf"> <id property="uId" column="uId" /> <result property="uName" column="uName"/> <result property="uSnId" column="uSnId"/> <result property="upassword" column="upassword"/> <association property="face" javaType="UserFace"> <result property="url" column="url" /> </association> </resultMap> <update id="initDB"> </update> <select id="getInfo" resultMap="Map_UserInf"> select inf.uId,inf.uName,face.id faceId,face.url faceUrl from db_user.tb_user_inf inf left join db_user.tb_user_face face on inf.face_id=face.id where uId=#{uId} limit 1 </select> <select id="findAllFaceUrl" resultMap="Map_UserInf2"> select inf.uName,inf.uId,inf.uSnId,inf.upassword,face.url from db_user.tb_user_inf inf inner join db_user.tb_user_face face on inf.face_id=face.id </select> </mapper> src/main/resources/mapper/PermitGroupUserMapper.xml
New file @@ -0,0 +1,13 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.whyc.mapper.PermitGroupUserMapper" > <select id="getPermitByUser" resultType="com.whyc.pojo.PermitGroup"> select tb_user_permitgroup.num,permit_group_name,permit_item_name,permit_item_value from db_user.tb_user_permitgroup,db_user.tb_user_permitgroup_data where tb_user_permitgroup.permit_group_id=tb_user_permitgroup_data.permit_group_id and tb_user_permitgroup_data.uId=#{userId} and tb_user_permitgroup.permit_item_value=1 </select> </mapper>