又一经典开源项目Guns完全解读,小Hub好棒!

Guns第三节 项目介绍 guns-admin是Guns管理系统guns-core是其他模块提炼出来的公共的代码guns-parent是maven的的父模块,父模块的作用就是管理其它的子模块,可以把我们依赖都提到parent,并且对我们依赖的版本做一个统一的维护。当我们的其他模块引用pom.xml的时候,是不带版本号的这就是parent模块的作用,他可以统一维护依赖的版本,gun-rest本意是些一个app 服务端,提供r... 阅读详情
小Hub领读:

guns这个项目相信很多人都知道,不知道你们有没完整读过呢,今天一起跟着小Hub来学习下哈。

一共几个主要模块比较重要:

  • map + warpper模式

  • Api数据传输安全

  • 数据范围限定


简介

Guns基于SpringBoot 2,致力于做更简洁的后台管理系统。Guns项目代码简洁,注释丰富,上手容易,同时Guns包含许多基础模块(用户管理,角色管理,部门管理,字典管理等10个模块),可以直接作为一个后台管理系统的脚手架!

官网:https://www.stylefeng.cn

本次解读版本:tag-v4.2版本,因为5.0后的项目都是maven单项目,核心类都封装到jar中了,所以学习的话最好使用v4.2的最后一版本maven多模块项目学习。

  • https://gitee.com/stylefeng/guns/tree/v4.2/

图片

项目特点

  1. 基于SpringBoot,简化了大量项目配置和maven依赖,让您更专注于业务开发,独特的分包方式,代码多而不乱。

  2. 完善的日志记录体系,可记录登录日志,业务操作日志(可记录操作前和操作后的数据),异常日志到数据库,通过@BussinessLog注解和LogObjectHolder.me().set()方法,业务操作日志可具体记录哪个用户,执行了哪些业务,修改了哪些数据,并且日志记录为异步执行,详情请见@BussinessLog注解和LogObjectHolder,LogManager,LogAop类。

  3. 利用beetl模板引擎对前台页面进行封装和拆分,使臃肿的html代码变得简洁,更加易维护。

  4. 对常用js插件进行二次封装,使js代码变得简洁,更加易维护,具体请见webapp/static/js/common文件夹内js代码。

  5. 利用ehcache框架对经常调用的查询进行缓存,提升运行速度,具体请见ConstantFactory类中@Cacheable标记的方法。

  6. controller层采用map + warpper方式的返回结果,返回给前端更为灵活的数据,具体参见com.stylefeng.guns.modular.system.warpper包中具体类。

  7. 简单可用的代码生成体系,通过SimpleTemplateEngine可生成带有主页跳转和增删改查的通用控制器、html页面以及相关的js,还可以生成Service和Dao,并且这些生成项都为可选的,通过ContextConfig下的一些列xxxSwitch开关,可灵活控制生成模板代码,让您把时间放在真正的业务上。

  8. 控制器层统一的异常拦截机制,利用@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 。


(完)

MarkerHub文章索引:(点击阅读原文直达)

https://github.com/MarkerHub/JavaIndex
【推荐阅读】
前、后端分离权限控制设计与实现
高中生也能读懂的Docker入门教程
终于有人把 HTTPS 原理讲清楚了!
超详细!4小时开发一个SpringBoot+vue前后端分离博客项目!!
知乎问答:难道非得包装简历?可是做不来~

好文章!点个在看!

企业级应用框架guns架构与开发实践 本文还有配套的精品资源,点击获取 简介:在IT领域,企业架构是组织信息和技术集成设计的关键。"guns"项目提供了一套高效、灵活且可扩展的企业管理架构设计框架。本文深入探讨guns项目的核心特性、应用场景和开发实践,以及如何使用不同的集成开发环境(IDE)进行项目开发。guns基于Spring Boot框架,集成MyBatis和Shiro,简化了微服务开发和权限控制,确保了... 阅读详情

相关推荐

guns开源项目企业版

Guns基于Spring Boot2,致力于做更简洁的后台管理系统。包含系统管理,代码生成,多数据库适配,SSO单点登录,工作流,短信,邮件发送,OAuth2登录,任务调度,持续集成,docker部署等功。支持Spring Cloud Alibaba微服务。社区活跃,版本迭代快,加群免费技术支持。 1.用户管理 2.角色管理 3.部门管理 4.菜单管理 5.字典管理 6.业务日志 7.登录日志 8.监控管理 9.通知管理 10.职务管理 11.代码生成 12.在线参数配置

国内优秀开源框架Guns框架入门学习

Guns下载路径:https://gitee.com/naan1993/guns一、Guns简介     Guns是国内一个非常优秀的开源框架,功能就是快速搭建后台应用系统,Guns基于SpringBoot,致力于做更简洁的后台管理系统,完美整合springmvc + shiro + mybatis-plus + beetl + flowable!Guns项目代码简洁,注释丰富,上手容易,同时Gu...

Champion-Dai 3万+

Revit模型转点云全流程:从OBJ导出到CloudCompare点云生成(2020版)

本文详细介绍了将Revit模型转换为点云数据的完整流程,特别针对Revit 2020用户。通过使用OBJ导出插件和开源软件CloudCompare,实现从模型导出、网格采样到生成结构化PCD点云的全过程,并提供了关键参数设置与常见问题解决方案,为BIM与三维数字孪生应用提供技术支持。

oo7890的博客 154

GitHub首次开源标星20k+项目:Guns-现代化主流Java应用开发框架

cn.stylefeng.roses kernel-s-devops-integration ${roses.kernel.version}

m0_63437643的博客 1330

【Milvus】实战指南:利用milvus-backup实现高效数据备份与恢复

本文详细介绍了如何利用官方工具milvus-backup为Milvus向量数据库实施高效的数据备份与恢复。文章从备份的必要性出发,逐步讲解了环境准备、配置要点、全量与按需备份操作,以及恢复数据的关键步骤和验证方法,旨在帮助用户构建可靠的数据安全防线,应对误操作或系统故障风险。

weixin_29217235的博客 131

《科研伦理与学术规范》 全部 习题_答案 2020年秋

科研伦理与学术规范 答案 文章目录科研伦理与学术规范 答案1. 第一章课后习题(必做) 答案1.1 第一章Demo2. 第二章课后习题(必做) 答案3. 第三章课后习题(必做) 答案4. 第四章课后习题(必做) 答案5. 第五章课后习题(必做) 答案6. 第六章课后习题(必做) 答案 # 每行5题 #写于2020.11.17 侵删 1. 第一章课后习题(必做) 答案 ABC, A, B ,D ,ABCD ABC, D, A, BCD, C D, D, 1.1 第一章Demo

羊老羊 25万+

guns框架字典取值_又一经典开源项目Guns完全解读,小Hub好棒!

小Hub领读:guns这个项目相信很多人都知道,不知道你们有没完整读过呢,今天一起跟着小Hub来学习下哈。一共几个主要模块比较重要:map + warpper模式Api数据传输安全数据范围限定简介Guns基于SpringBoot 2,致力于做更简洁的后台管理系统。Guns项目代码简洁,注释丰富,上手容易,同时Guns包含许多基础模块(用户管理,角色管理,部门管理,字典管理等10个模块),...

weixin_31002059的博客 443

YOLO12涨点改进| 损失函数改进篇 |AAAI 2025| 一种小目标检测SDLoss损失函数,解决现有损失函数对不同目标尺度敏感度不足的局限,提高了网络检测不同尺度目标的敏感能力,助力高效涨点

本文提出了一种改进的小目标检测方法SDLoss,通过动态调整尺度损失与位置损失的权重,优化了YOLOv12模型的性能。针对红外小目标检测中存在的两个主要问题:1)标准卷积难以捕捉目标的高斯空间分布特性;2)现有损失函数对不同尺度目标的敏感度不足,研究团队开发了Pinwheel-shaped卷积(PConv)和Scale-based Dynamic损失函数(SDLoss)。PConv通过不对称卷积核设计显著提升感受野,SDLoss则根据目标大小动态平衡尺度与位置损失的影响。

Ai缝合怪、助力小伙伴高效发论文 238

android经典简单小项目_又一经典开源项目Guns完全解读,小Hub好棒!

小Hub领读:guns这个项目相信很多人都知道,不知道你们有没完整读过呢,今天一起跟着小Hub来学习下哈。一共几个主要模块比较重要:map + warpper模式Api数据传输安全数据范围限定简介Guns基于SpringBoot 2,致力于做更简洁的后台管理系统。Guns项目代码简洁,注释丰富,上手容易,同时Guns包含许多基础模块(用户管理,角色管理,部门管理,字典管理等10个模块),...

weixin_42468240的博客 578

HanLP的分词

HanLP的分词

sikh_0529的博客 1万+

OCR文字识别领域经典论文总结

本篇将介绍文字识别经典论文,内容包括文字检测、文字识别、端到端识别等方法,具体将分别对论文算法简介、思路、代码等几个部分展开介绍。目前各部分只举例经典论文,算法没有全部写完,后续会将在此部分基础上更新更多论文综述及代码实战部分。.................................

专注大数据与人工智能技术分享,欢迎私信加群互相学习! 1万+

guns框架字典取值_基于SpirngBoot的企业级后台管理框架Guns完整解析

小Hub领读:guns这个项目相信很多人都知道,不知道你们有没完整读过呢,今天一起跟着小Hub来学习下哈。一共几个主要模块比较重要:map + warpper模式Api数据传输安全数据范围限定简介Guns基于SpringBoot 2,致力于做更简洁的后台管理系统。Guns项目代码简洁,注释丰富,上手容易,同时Guns包含许多基础模块(用户管理,角色管理,部门管理,字典管理等10个模块),可以直接作...

weixin_36320737的博客 419

Python爬虫实战:亚马逊中国模拟登录与二次验证全解析(2026最新版)

在数据驱动的商业时代,亚马逊作为全球最大的电商平台,其商品数据、价格波动、评论信息、库存状态等对市场分析、竞品研究、价格监控具有极高的价值。然而,亚马逊的反爬虫机制堪称行业标杆——从请求指纹校验、动态令牌、行为分析到二次验证(2FA),层层设防。本篇文章将带你从零开始,使用2026年最新的Python技术栈,完整实现亚马逊中国(z.cn)的模拟登录,并攻克二次验证难题。郑重声明:本文仅限技术研究与个人学习用途,严禁用于批量抓取、价格劫持、账户爆破等违法违规行为。

2201_76125261的博客 378

guns 最新开源框架企业版下载_十大Docker开源替代产品

点击上方“蓝字”关注我们吧!众所周知,在全球范围内,Docker已经发展成为云计算的核心技术之一。作为流行的容器管理技术,Docker的最大优点是能将应用与计算环境分离,允许开发者在同一台计算机上使用不同的技术。通过Docker,开发者可以使应用程序在同一服务器上运行Python、Ruby、PHP、Node JS或任何其他语言,并将每个应用程序安装在具备独立数据库引擎的单独容器中。但是,...

weixin_39621794的博客 338

基于咸鱼最新九宫格图标验证码的语义增强模型识别

本文探讨了破解复杂验证码的技术思路,重点分析了某平台的九宫格验证码应对策略。作者提出通过图像语义抽取和增强技术来扩充数据集:先采集少量真实样本,利用形态学操作进行前增强生成变形图像,再通过叠加背景噪声进行后增强。同时强调真实数据集的重要性,建议采用真实+生成数据的混合训练方法。实验表明该方法可使模型准确率达到95%以上,但作者特别声明本文仅供技术研究,严禁用于非法用途。

码王吴彦祖的博客 601

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

github基本使用

git回退到某一版本 git reflog 或 git log #查看历史版本 git reset --hard commit_id #回退到指定版本 git push -f -u origin branch_name #强制提交到该分支,将github上的head也指向该位置 ...

七七的博客 194

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

guns快速搭建后台管理系统

最近开发一个新项目,作为一个后台不得不说,项目拿到手我最不想写的模块就是后台管理系统,感觉就跟鞋裹脚布一样又臭又长,无穷无尽的增删查,想想就觉得没意思,但是写项目又逃不开它,没办法尽量找一个方便使用的后台管理系统框架吧,一个好的后台管理系统框架可以让我们少做很多事情,有跟多的时间来编写自己感兴趣的代码,下面就介绍一下guns这个方便的后台管理系统框架如何快速使用。 1、项目可以从...

向阳居士的博客 6931

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

guns快速入门

guns简介 Guns是国内一个非常优秀的开源框架,功能就是快速搭建后台应用系统,Guns基于SpringBoot,致力于做更简洁的后台管理系统,完美整合springmvc + shiro + mybatis-plus + beetl + flowable!Guns项目代码简洁,注释丰富,上手容易,同时Guns包含许多基础模块(用户管理,角色管理,部门管理,字典管理等10个模块),可以直接作为...

清欢 2528

Guns简介

1、Guns是什么? Guns基于Spring Boot2,致力于做更简洁的后台管理系统。 Guns包含系统管理,代码生成,多数据库适配,SSO单点登录,工作流,短信,邮件发送,OAuth2登录,任务调度,持续集成,docker部署等功能,支持Spring Cloud Alibaba微服务。 2、Guns整合了哪些组件? 2.1、springboot 英文文档:https://spring.io/...

weixin_44605704的博客 1万+

关于guns框架的基本配置以及自动生成代码的使用

1、项目准备 1.克隆项目: git clone https://github.com/stylefeng/Guns.git **2.数据库准备: ** 建立一个 guns 数据库,执行官方sql: https://github.com/stylefeng/Guns/blob/master/guns-admin/sql/guns.sql **3.修改数据源: ** 修改其中的所有数据源为你的 ——...

过于丰富,无法简介 3554

7.17 Guns、页面制作、Jquery框架+bootstrap框架、图表制作

Guns、页面制作、Jquery框架+bootstrap框架、图表制作

PYH的博客 1671

Guns框架基本介绍、下载、部署

什么是Guns? 1、快速构建后台管理系统的框架(注意:是后台管理系统) 2、Guns默认提供诸多业务系统的基本功能 3、Guns集成诸多优秀的开源框架 基本功能 权限管理(用户管理,角色管理,部门管理) 菜单管理,字典管理,业务日志,登录日志,监控管理,通知管理,代码生成(核心) Guns的部署 ...

blogliban的博客 4985

Guns 项目教程

Guns 是一个基于 SpringBoot 的后台管理系统框架,致力于提供简洁、易用的后台管理解决方案。Guns 完美整合了 SpringMVC、Shiro、分页插件 PageHelper、通用 Mapper 和 Beetl 模板引擎。项目代码简洁,注释丰富,上手容易,同时包含了用户管理、角色管理、部门管理、字典管理等10个基础模块,可以直接作为一个后台管理系统的脚手架。 ## 2. 项目快速启

gitblog_00136的博客 1166

Guns快速开发平台开发环境搭建

官网地址:Guns快速开发平台 下载源码:Guns: Guns基于Spring Boot2,致力于做更简洁的后台管理系统。支持单体和微服务架构。Guns 7.0全新升级。 解压: 使用idea打开项目: 配置本地maven: 等待依赖下载完成。 以下插件未安装成功: 加入版本号即可: 安装lombok插件: 修改本地mysql数据库配置信息: 新建guns数据库: 运行系统: 运行成功: 账号:admin ...

低码开发 1763

Guns框架:基于主流技术Spring Boot2 + Vue3 + Antd Vue的现代Java应用开发新纪元

Guns是一个现代化的Java应用开发框架,基于主流技术Spring Boot2 + Vue3 + Antd Vue,Guns基于插件化架构,通过灵活组装插件,可以进行集成和拓展相关功能。Guns v7.3.1已经发布,前后端代码以及核心包源码,均可在如下Gitee仓库可找到:前端代码:https://gitee.com/stylefeng/guns-vue3-admin后端代码:https://gitee.com/stylefeng/guns。

chenchuang0128的博客 2491
上一篇: 大厂面试必问的4大框架源码,你真会么?
下一篇: 有了这个 IDEA的兄弟,你还用 Navicat 吗?全家桶不香吗?
Java思维导图
博客等级 码龄10年 306粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值