首页 文章 精选 留言 我的

精选列表

搜索[企业级],共10000篇文章
优秀的个人博客,低调大师

Next.js 12.1 正式发布,企业级 Web 应用框架

Next.js 12.1 已正式发布。 新特性概览 按需使用的 ISR (Beta):支持即时使用getStaticProps重新验证页面 扩展对 SWC 的支持:引入styled-components和 Relay 等功能 引入next/jest插件:使用 SWC 实现零配置支持 Jest 通过 SWC (RC) 提供更快的压缩:比 Terser 快 7 倍的压缩速度 优化自托管功能:减小 Docker 镜像体积约 80% React 18 & Server Components (Alpha):优化稳定性和支持情况 按需使用的 ISR (Beta) ISR 是 Next.js 9.5 引入的功能,本次的更新提供了按需使用的特性,开发者可按需手动清除特定页面的 Next.js 缓存。 // pages/api/revalidate.js export default async function handler(req, res) { // Check for secret to confirm this is a valid request if (req.query.secret !== process.env.MY_SECRET_TOKEN) { return res.status(401).json({ message: 'Invalid token' }) } try { await res.unstable_revalidate('/path-to-revalidate') return res.json({ revalidated: true }) } catch (err) { // If there was an error, Next.js will continue // to show the last successfully generated page return res.status(500).send('Error revalidating') } } 零配置 Jest 插件 Next.js 现已支持自动配置 Jest,使用基于 Rust 的 Next.js 编译器来转换文件,包括: 自动模拟样式表(.css,.module.css和.scss变体),以及图像导入 将.env加载到process.env 忽略测试解析和转换的node_modules 忽略测试解析的.next Loadingnext.config.jsfor flags that enable Next.js compiler transforms 优化自托管功能 Next.js 现在支持自动创建standalone文件夹,该文件夹仅复制生产部署所需的文件。这使得自托管 Next.js 应用程序的Docker 映像缩小了约 80% 。 详情查看 release note。

优秀的个人博客,低调大师

ShopXO 企业级免费开源商城 v2.2.4 正式发布

更新日志 1. 商品url地址优化 2. 商品购买类型判断优化 3. 用户管理列表新增邀请人id 4. 后台用户新增及更新调用统一方法 5. 优化0元订单无需选择支付方式 6. 底层js类库更新+框架底层更新 7. 小程序商品详情页支持返回指定操作 8. 后台统计数据优化 9. 商品保存规格判断错误修复 10. 文章优化 11. 分页组件xss修复 12. excel库更新为Spreadsheet库支持更高版本、效率更高、更稳定 13. 动态数据列表处理模块优化+支持Ym年月选择条件 14. 订单商品类型校验错误修复 15. 日历组件更新到最新版本 16. 表单验证器优化 17. 浏览文件库存配置添加提示、下单商品新增扩展内容 18. 订单售后商品异常影响优化 19. 新增支付宝和微信付款码支付(一般用于线下扫用户付款码进行支付) 20. 新增插件权限单独配置管理 21. 新增电子营业执照亮证 22. 新增web端PC访问关闭开关 23. 新增json头信息系统出错输出 24. 门店2.0.0版本开发支持大多数O2O实体店运营、线上线下完美结合 效果图片(内置多种配色) 可视化DIY拖拽装修展示 PC端展示 后台管理展示

优秀的个人博客,低调大师

ShopXO 企业级免费开源商城 v2.2.3 正式发布

更新日志 本次更新主要更新新版本主题适配H5端 1. 整体适配H5端 2. 订单、钱包、会员等级支付优化适配 3. 支持(账号、手机、邮箱)登录注册方式 4. 分享逻辑优化全局处理 5. 分销新增上级用户、阶梯返佣提示 6. 新增独立新增错误页面 7. 适配第三方登录插件 8. 支持线下支付自定义信息展示 9. 规格切换购买数量错误修复 10. 手机端富文本详情支持视频、超链接、图片预览 11. 页面设计图片地址处理优化 12. 问答数据处理用户出错修复 13. 新增web端首页关闭状态+新增电信经营许可证展示 14. 支持新增线下支付订单进入正常流程开关 15. 新增手机H5自定义地址 16. 商店账号未绑定优化 17. 订单自动收货参数错误修复 18. 老版本小程序主题适配新版本接口 效果图片(内置多种配色) 可视化DIY拖拽装修展示 PC端展示 后台管理展示

优秀的个人博客,低调大师

ShopXO 企业级免费开源商城 v2.2.2 正式发布

更新日志 本次更新主要新版本小程序主题全面支持(微信、支付宝、百度、头条&抖音、QQ)6大平台小程序、并适配所有功能插件 1. 限时秒杀插件支持独立首页并适配小程序 2. 活动配置插件支持优惠价格设定并适配小程序 3. 标签插件适配小程序 4. 中间广告插件适配小程序 5. 弹屏广告插件适配小程序 6. 哀悼插件适配小程序 7. 文章支持分类页面并适配小程序 8. 博客插件适配小程序 9. 分销、会员等级增强版、钱包全面支持小程序 10. 新增批量评价插件 11. 新增用户授权获取用户信息API 12. 可视化商品分类排序错误修复 13. 百度支付插件支持自定义异步地址 14. 新增菜鸟物流插件、支持web端和小程序 15. 第三方登陆插件APP端支持(微信、QQ) 16. 插件隐私字段配置、避免重要信息暴露 小程序效果图片 可视化DIY拖拽装修展示 PC端展示 后台管理展示

优秀的个人博客,低调大师

Diboot 2.3.1 发布,易上手的企业级低代码开发平台

Diboot是为开发者所打造的一个低代码开发平台,一个数倍提效的赋能工具。 Diboot不但拥有从前端到后端的整个基础架构,帮你更快开展项目。而且还拥有开发过程中的前后端一系列已有组件,助你少造轮子。还具有一套自动化工具,在开发过程中,前后端方面都可以帮您提质增效。 Diboot将致力于有效提高软件的代码质量、开发效率、可维护性,同时也对其打造了自动化工具来完成系列重复工作和复杂工作。 Diboot将通过系列基础组件化繁为简,又通过高效工具以简驭繁。 更新重点 core内核支持字段加密与脱敏,安全等保放心用 移动端发布: 后端基础组件diboot-mobile-starter 和 配套前端UI diboot-mobile-ui scheduler定时任务组件支持开关日志、自定义名称等系列优化 devtools前端生成新增支持关联场景的集成方案,使面板组件易于集成 devtools前端代码生成后支持自动格式化 devtools前端列表生成支持可选editable可编辑表格 升级依赖版本:spring boot 2.5.5, mybatis-plus 3.4.3.4,shiro 1.8.0 微服务 diboot-cloud v2.3.1版本同步升级 (企业版用户可参考docs下的文档升级) 系列优化与改进,可见如下更新详情 diboot-core & diboot-core-starter 🎉 新增: 新增@ProtectField注解实现字段加密与脱敏,支持安全等保 BindEntityList新增支持多个ID拼接存储的值进行拆解绑定 BindFieldList新增支持orderBy排序 新增diboot.global.init-sql全局配置,关闭sql自动初始化检查 新增InvalidUsageException用于提示错误的调用 🍻 优化: 优化请求参数的合法检查、异常信息过滤等安全防护 优化PagingJsonResult添加空构造方法,便于反序列化 优化BaseService的N-N更新接口实现 升级依赖版本:spring boot 2.5.5, mybatis-plus 3.4.3.4... 🐛 修复: Fix bug: 优化select字段逻辑特定情况下误转换有AS别名字段的问题 文件组件 diboot-file-starter v2.3.1 🍻 优化: 优化文件类型黑白名单及合法检查逻辑 IAM组件 diboot-IAM-starter v2.3.1 🎉新增: 新增IamSecurityUtils.getCurrentUserId(),直接返回用户id 🍻 优化: 优化异步日志保存类,指定异步executor,避免多异步执行器场景下冲突 用户角色更新接口实现逻辑优化 升级依赖版本: shiro1.8.0 🐛 修复: Fix bug: 下载接口添加@log日志注解报异常问题 消息通知组件 diboot-message-starter v2.3.1 🍻 优化: 邮件通道默认支持发送HTML格式邮件 优化异步日志保存类,指定executor,避免多异步执行器场景下冲突 优化message的模板id允许为空,支持不依赖模板的消息记录 定时任务组件 diboot-scheduler-starter v2.3.1 🍻 优化: 新增createByName字段冗余,移除IAM依赖 定时任务对象新增saveLog是否记录日志开关 定时任务名称支持自定义及模糊查询 优化异步日志保存类,指定executor,避免多异步执行器场景下冲突 移动端组件 diboot-mobile-starter (新组件) v2.3.1 支持H5账号密码登录、微信小程序登录与注册、微信公众号登录与注册 组件自动配置,iam-member移动端成员表自动初始化 提供配套 diboot-mobile-ui (uni-app版) 前端框架 移动端前端 diboot-mobile-ui (新项目) v2.3.1 基于uni-app基础轻量封装 支持H5账号密码登录 支持微信小程序登录与自动注册 支持微信公众号登录与自动注册 PC前端 diboot-antd-admin v2.3.1 🍻 优化: 调整attachMore请求逻辑,兼容自定义attachMore和通用attachMore接口 新增自定义开区间查询 定时任务支持配置标题及日志开关 新增可编辑表格 调整文件上传大小为10M 引入图片预览组件 🐛 修复: Fix bug: 点击上传的文件项弹窗异常问题 PC前端 diboot-element-admin v2.3.1 🍻 优化: 调整attachMore请求逻辑,兼容自定义attachMore和通用attachMore接口 新增自定义开区间查询 定时任务支持配置标题及日志开关 新增可编辑表格 调整文件上传大小为10M 工具 diboot-devtools v2.3.1 🎉 新增: 前端生成新增支持关联场景的集成方案,使面板组件易于集成 前端代码生成后自动格式化 前端列表生成支持可选editable可编辑表格 🍻 优化: 支持PostgreSQL 12+版本 N-N关联配置支持自定义属性名 字段自动填充实现改为生成MP的MetaObjectHandler实现类 🐛 修复: fix:1-n的详情页设置保存快照后恢复回显异常问题 fix:后端代码删除后,之前的关联设置未能正确回显的问题 fix:非id,uuid主键的已有表生成后端代码报错的问题 微服务 diboot-cloud v2.3.1 🎉 新增: 用户列表新增excel上传下载功能 🍻 优化: 配置简化优化,包路径优化,common基础组件改为starter,增加自动配置,业务模块无需再配置scan "com.diboot" auth-server中的resource server配置移至yml中 scheduler定时任务新增saveLog是否记录日志开关,定时任务名称支持自定义及模糊查询 message模块邮件通道支持发送HTML格式邮件 依赖升级 🐛 修复: fix:图片文件下载的弹窗预览异常问题

优秀的个人博客,低调大师

基于SpirngBoot的企业级后台管理框架Guns完整解析

小Hub领读: guns这个项目相信很多人都知道,不知道你们有没完整读过呢,今天一起跟着小Hub来学习下哈。 一共几个主要模块比较重要: map + warpper模式 Api数据传输安全 数据范围限定 视频讲解:https://www.bilibili.com/video/BV1P5411j7yA/ 简介 Guns基于SpringBoot 2,致力于做更简洁的后台管理系统。Guns项目代码简洁,注释丰富,上手容易,同时Guns包含许多基础模块(用户管理,角色管理,部门管理,字典管理等10个模块),可以直接作为一个后台管理系统的脚手架! 官网:https://www.stylefeng.cn 视频讲解:https://www.bilibili.com/video/BV1P5411j7yA/ 本次解读版本:tag-v4.2版本,因为5.0后的项目都是maven单项目,核心类都封装到jar中了,所以学习的话最好使用v4.2的最后一版本maven多模块项目学习。 https://gitee.com/stylefeng/guns/tree/v4.2/ 项目特点 基于SpringBoot,简化了大量项目配置和maven依赖,让您更专注于业务开发,独特的分包方式,代码多而不乱。 完善的日志记录体系,可记录登录日志,业务操作日志(可记录操作前和操作后的数据),异常日志到数据库,通过@BussinessLog注解和LogObjectHolder.me().set()方法,业务操作日志可具体记录哪个用户,执行了哪些业务,修改了哪些数据,并且日志记录为异步执行,详情请见@BussinessLog注解和LogObjectHolder,LogManager,LogAop类。 利用beetl模板引擎对前台页面进行封装和拆分,使臃肿的html代码变得简洁,更加易维护。 对常用js插件进行二次封装,使js代码变得简洁,更加易维护,具体请见webapp/static/js/common文件夹内js代码。 利用ehcache框架对经常调用的查询进行缓存,提升运行速度,具体请见ConstantFactory类中@Cacheable标记的方法。 controller层采用map + warpper方式的返回结果,返回给前端更为灵活的数据,具体参见com.stylefeng.guns.modular.system.warpper包中具体类。 简单可用的代码生成体系,通过SimpleTemplateEngine可生成带有主页跳转和增删改查的通用控制器、html页面以及相关的js,还可以生成Service和Dao,并且这些生成项都为可选的,通过ContextConfig下的一些列xxxSwitch开关,可灵活控制生成模板代码,让您把时间放在真正的业务上。 控制器层统一的异常拦截机制,利用@ControllerAdvice统一对异常拦截,具体见com.stylefeng.guns.core.aop.GlobalExceptionHandler类。 技术选型 springboot mybatis plus shiro beetl ehcache jwt 模块分析 学习一个项目就是学习项目的亮点地方,在分析guns的过程中,有些地方值得我们学习,下面我们一一来分析: map + warpper模式 访问后台的用户列表时候,我们通常需要去查询用户表,但是用户表里面有些外键,比如角色信息、部门信息等。因此有时候我们查询列表时候一般在mapper中关联查询,然后得到记录。 官网介绍: map+warpper方式即为把controller层的返回结果使用BeanKit工具类把原有bean转化为Map的的形式(或者原有bean直接是map的形式),再用单独写的一个包装类再包装一次这个map,使里面的参数更加具体,更加有含义,下面举一个例子,例如,在返回给前台一个性别时,数据库查出来1是男2是女,假如直接返回给前台,那么前台显示的时候还需要增加一次判断,并且前后端分离开发时又增加了一次交流和文档的成本,但是采用warpper包装的形式,可以直接把返回结果包装一下,例如动态增加一个字段sexName直接返回给前台性别的中文名称即可。 guns项目中,作者说独创了一种map+warpper模式。我们来看下是如何实现的。 看看下UserController的代码: /** * 查询管理员列表 */ @RequestMapping("/list") @Permission @ResponseBody public Object list(@RequestParam(required = false) String name , @RequestParam(required = false) String beginTime , @RequestParam(required = false) String endTime , @RequestParam(required = false) Integer deptid) { if (ShiroKit.isAdmin()) { List<Map<String, Object>> users = userService.selectUsers(null, name, beginTime, endTime, deptid); return new UserWarpper(users).warp(); } else { DataScope dataScope = new DataScope(ShiroKit.getDeptDataScope()); List<Map<String, Object>> users = userService.selectUsers(dataScope, name, beginTime, endTime, deptid); return new UserWarpper(users).warp(); } } userService.selectUsers中只是一个单表的查询操作,没有关联其他表,因此查询出来的结果中有些字段需要手动转换,比如sex、roleId等,因此作者定义了一个UserWarpper,用来转换这些特殊字段,比如sex存的0转成男,roleId查库之后转成角色名称等。 /** * 用户管理的包装类 * * @author fengshuonan * @date 2017年2月13日 下午10:47:03 */ public class UserWarpper extends BaseControllerWarpper { public UserWarpper(List<Map<String, Object>> list) { super(list); } @Override public void warpTheMap(Map<String, Object> map) { map.put("sexName", ConstantFactory.me().getSexName((Integer) map.get("sex"))); map.put("roleName", ConstantFactory.me().getRoleName((String) map.get("roleid"))); map.put("deptName", ConstantFactory.me().getDeptName((Integer) map.get("deptid"))); map.put("statusName", ConstantFactory.me().getStatusName((Integer) map.get("status"))); } } 因为mybatis plus支持查询返回map的形式,所以只需要把map传进来,就可以转换成功,如果查询结果是一个实体的bean,那就先转成map,然后再用warpTheMap。其中BaseControllerWarpper也是一个关键抽象类,提供转换结果。 日志模块 日志记录采用aop(LogAop类)方式对所有包含@BussinessLog注解的方法进行aop切入,会记录下当前用户执行了哪些操作(即@BussinessLog value属性的内容)。 如果涉及到数据修改,会取当前http请求的所有requestParameters与LogObjectHolder类中缓存的Object对象的所有字段作比较(所以在编辑之前的获取详情接口中需要缓存被修改对象之前的字段信息),日志内容会异步存入数据库中(通过ScheduledThreadPoolExecutor类)。 日志注解标识:com.stylefeng.guns.core.common.annotion.BussinessLog 日志处理切面:com.stylefeng.guns.core.aop.LogAop 日志记录字段字典:com.stylefeng.guns.core.common.constant.dictmap.base.AbstractDictMap 任务式保存记录:LogManager.me().executeLog(TimerTask task) jwt校验 在之前的课程中,我们已经说过了很多次jwt的形式作为用户的token,在这项目中,jwt讲到了与Api的数据传输安全结合起来一起运用。首先我们看下guns-rest项目,打开com.stylefeng.guns.rest.modular.auth.controller.AuthController,这个类是客户端调用登录生成Jwt的地方。 @RestController public class AuthController { @Autowired private JwtTokenUtil jwtTokenUtil; @Resource(name = "simpleValidator") private IReqValidator reqValidator; /** * 请求生成jwt * * @param authRequest * @return */ @RequestMapping(value = "${jwt.auth-path}") public ResponseEntity<?> createAuthenticationToken(AuthRequest authRequest) { boolean validate = reqValidator.validate(authRequest); if (validate) { final String randomKey = jwtTokenUtil.getRandomKey(); final String token = jwtTokenUtil.generateToken(authRequest.getUserName(), randomKey); return ResponseEntity.ok(new AuthResponse(token, randomKey)); } else { throw new GunsException(BizExceptionEnum.AUTH_REQUEST_ERROR); } } } 来说明一下上面的代码: IReqValidator :账号密码校验器 DbValidator SimpleValidator randomKey :随机生成的key,用于数据安全校验 token:生成保护用户id的jwt 所以app登录调用这接口生成的值如下: { "randomKey": "1jim2v", "token": "eyJhbGciOiJIUzUxMiJ9.eyJyYW5kb21LZXkiOiIxamltMnYiLCJzdWIiOiJhZG1pbiIsImV4cCI6MTU2MjM5NjgwNCwiaWF0IjoxNTYxNzkyMDA0fQ.vr3HwhV_e8MrpNZY0rxbqs1cOzHIBdon4cQT-Gs9wvmv8UZEBbc4QNSMxTh_ulcVpkaw2uwZY4_8zJ7I2G-36Q" } 好了,客户端拿到token之后,每次请求需要在header中把token带上,然后服务过滤器校验 AuthFilter:校验jwt是否过期和是否正确 //验证token是否过期,包含了验证jwt是否正确 boolean flag = jwtTokenUtil.isTokenExpired(authToken); ok,jwt的生成和校验逻辑都很简单,下面我们来说说接口传输安全是怎么做到的。 Api数据传输安全 上面我们说到客户端登录之后拿到了一个token和randomKey,token是用来校验用户身份的,那么这个randomKey是用来干嘛的呢,其实是用来做数据安全加密的。 当开启传输安全模式时候,客户端发送数据给服务器的时候会进行加密传输,具体的加密过程,guns中有一个com.stylefeng.guns.jwt.DecryptTest: public static void main(String[] args) { String salt = "1jim2v"; SimpleObject simpleObject = new SimpleObject(); simpleObject.setUser("stylefeng"); simpleObject.setAge(12); simpleObject.setName("ffff"); simpleObject.setTips("code"); String jsonString = JSON.toJSONString(simpleObject); String encode = new Base64SecurityAction().doAction(jsonString); String md5 = MD5Util.encrypt(encode + salt); BaseTransferEntity baseTransferEntity = new BaseTransferEntity(); baseTransferEntity.setObject(encode); baseTransferEntity.setSign(md5); System.out.println(JSON.toJSONString(baseTransferEntity)); } 上面的过程就是把simpleObject 对象进行new Base64SecurityAction().doAction自定义加密(可自定义,项目只是简单Base64编码),然后加把加密后的值和salt进行Md5计算,得出来的md5就是签名,那么这个salt是哪里来的呢,其实这个salt的值就是randomKey的值。 DataSecurityAction:加密、解密的抽象类 Base64SecurityAction:其中一种实现,简单的Base64编码完成加密解密 如果其他方式的直接实现DataSecurityAction即可 上面的main方法运行之后得到的值如下: {"object":"eyJhZ2UiOjEyLCJuYW1lIjoiZmZmZiIsInRpcHMiOiJjb2RlIiwidXNlciI6InN0eWxlZmVuZyJ9", "sign":"34bdd49a0838b1ef69cca928d71e885d"} 因此,客户端就是把这串数据传送到服务器: 注意要填请求头:Authorization的值是:Bearer+空格+token,这个可以从AuthFilter中知道 好了,上面发送给hello接口,那么我们看下是如何接收和解密的,首先来看下接口: @Controller @RequestMapping("/hello") public class ExampleController { @RequestMapping("") public ResponseEntity hello(@RequestBody SimpleObject simpleObject) { System.out.println(simpleObject.getUser()); return ResponseEntity.ok("请求成功!"); } } 貌似没啥特殊的,参数SimpleObject应该是解析之后得到的值得,我们都知道,我们把参数写到控制器中时候,spring会自动帮我们完成参数注入到实体bean的过程,我们传过来的是一个加密的json,spring是帮不了我们自动解析的,因此,这里我们要做个手动转换json(解密)的过程,再完成注入; 先来分析一下spring的过程:在springboot项目里当我们在控制器类上加上@RestController注解或者其内的方法上加入@ResponseBody注解后,默认会使用jackson插件来返回json数据。 因此我们需要实现手动转成json与bean,只需要继承FastJsonHttpMessageConverter,重写read的过程。 guns项目中有WithSignMessageConverter 这样一个类: /** * 带签名的http信息转化器 * * @author fengshuonan * @date 2017-08-25 15:42 */ public class WithSignMessageConverter extends FastJsonHttpMessageConverter { @Autowired JwtProperties jwtProperties; @Autowired JwtTokenUtil jwtTokenUtil; @Autowired DataSecurityAction dataSecurityAction; @Override public Object read(Type type, Class<?> contextClass , HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { InputStream in = inputMessage.getBody(); Object o = JSON.parseObject(in, super.getFastJsonConfig().getCharset(), BaseTransferEntity.class, super.getFastJsonConfig().getFeatures()); //先转化成原始的对象 BaseTransferEntity baseTransferEntity = (BaseTransferEntity) o; //校验签名 String token = HttpKit.getRequest().getHeader(jwtProperties.getHeader()).substring(7); String md5KeyFromToken = jwtTokenUtil.getMd5KeyFromToken(token); String object = baseTransferEntity.getObject(); String json = dataSecurityAction.unlock(object); String encrypt = MD5Util.encrypt(object + md5KeyFromToken); if (encrypt.equals(baseTransferEntity.getSign())) { System.out.println("签名校验成功!"); } else { System.out.println("签名校验失败,数据被改动过!"); throw new GunsException(BizExceptionEnum.SIGN_ERROR); } //校验签名后再转化成应该的对象 return JSON.parseObject(json, type); } } 分析:首先从body中获取到json数据,然后从header中获取到jwt的token(为了拿到randomKey),然后再Md5计算,比较传过来的sign,一致代表数据是没被串改过的,然后dataSecurityAction.unlock解密得到原始的json数据,最后调用JSON.parseObject(json, type);把json转成SimpleObject,所以整过过程就是这样,perfect。 数据范围限定 关于数据范围限定的概念很多人不知道,我们先来看下效果: 超级用户:admin登录查看用户列表 运营主管(运营部):test登录查看用户列表 从上面的两个登录账号中可以很直观看到,admin作为超级管理员,可以看到所有的数据,而test作为运营部的运营主管角色只能看到自己部门下的用户。 因此数据范围限定的意思就是根据用户的角色决定用户能查看的数据范围。 要完成这个功能有两个关键类: DataScope: public class DataScope { /** * 限制范围的字段名称 */ private String scopeName = "deptid"; /** * 具体的数据范围 */ private List<Integer> deptIds; ... } DataScopeInterceptor @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) public class DataScopeInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget()); MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler); MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement"); if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) { return invocation.proceed(); } BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql"); String originalSql = boundSql.getSql(); Object parameterObject = boundSql.getParameterObject(); //查找参数中包含DataScope类型的参数 DataScope dataScope = findDataScopeObject(parameterObject); if (dataScope == null) { return invocation.proceed(); } else { String scopeName = dataScope.getScopeName(); List<Integer> deptIds = dataScope.getDeptIds(); String join = CollectionKit.join(deptIds, ","); originalSql = "select * from (" + originalSql + ") temp_data_scope where temp_data_scope." + scopeName + " in (" + join + ")"; metaStatementHandler.setValue("delegate.boundSql.sql", originalSql); return invocation.proceed(); } } ... } 可以看出,其实就是一个mybatis的拦截器,拦截StatementHandler的prepare方法,然后在需要执行的sql外包装一层select * from(...)别名 where 别名.字段 in (范围)。 看起来逻辑还是挺清晰的。回头看下用户的list代码, DataScope dataScope = new DataScope(ShiroKit.getDeptDataScope()); List<Map<String, Object>> users = userService.selectUsers(dataScope, name, beginTime, endTime, deptid); 因此在需要数据范围限定的地方加上DataScope dataScope参数,拦截器会扫描参数中是否有 DataScope 类型,有的话就在sql外套上一层select * from,然后加上定义的字段限定范围。perfect~ 结束语 好了,这里是MarkerHub,我是小Hub吕一明。就解读到这里,更多开源项目解读可以上 httts://markerhub.com 。 推荐阅读: B站50K播放量,SpringBoot+Vue前后端分离完整入门教程! 分享一套SpringBoot开发博客系统源码,以及完整开发文档!速度保存! Github上最值得学习的100个Java开源项目,涵盖各种技术栈! 2020年最新的常问企业面试题大全以及答案

优秀的个人博客,低调大师

企业级 React 组件库 tinper-bee 发布 2.3.5 版本

🌟 时间控件 输入框格式校验修改,支持moment所有合法格式 🐞 Tooltip 解决宽度设置无效问题 🌟 Modal confirm类型新增第二种形式 🌟 优化 组件库 默认英文 🐞 修复 Table 组件 模态框中表格滚动条计算错误问题 查看详细升级内容:https://github.com/iuap-design/tinper-bee/releases/tag/2.3.5 iuap design 官网:点击查看 相关链接 tinper-bee 的详细介绍:点击查看 tinper-bee 的下载地址:点击下载

资源下载

更多资源
Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册