# leenmvc **Repository Path**: JohnCoding/leenmvc ## Basic Information - **Project Name**: leenmvc - **Description**: 基于springboot,mybatis、shiro等开发的简单易用的web后台框架。测试请使用postman。 - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: https://gitee.com/leen1993/leenmvc - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2023-03-16 - **Last Updated**: 2023-03-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # leen_springmvc ## 介绍 基于Spring+SpringMVC+Mybatis分布式敏捷开发系统架构。 1. 框架基于C3P0实现了对**多数据源**的框架自管控,开发者可以根据项目需要灵活地对项目的数据源进行配置和开发以满足分布式数据源的需求。并且对分布式数据源进行了事务控制保证数据的原子性。 2. 框架中对数据库的查询方法通过自封装的**SQL生成器**实现了SQL语句的自生成和控制,同时也支持Mybatis的Sql语句查询。 3. 框架中针对常用的接口比如getList, getAll, getById, kvs, sqlKvs, page等在实体、Dao文件、Service文件创建完成即自生成。还可根据自己项目的实际情况自定义自动生成接口。 4. 框架自实现了**API**生成机制,克服了SwaggerUI不能针对HashMap、request等形参生成相应的文档的问题。 5. 框架通过**shiro**安全框架实现了针对于角色、用户等层面的权限控制。 6. 框架实现了**@TopicMapping**注解,实现了对海量主题的分散有序处理。通过这个注解实现了主题之间的松耦合。 7. 框架基于传统的控制层、服务层和持久层分别做了对数据库查询的优化处理,使得数据库操作更加简单易用。 8. 框架支持mysql、SQLSERVER、oracle、iotdb等数据库。(oracle还未开发) 9. 框架中针对**docker**的部署方式,已经配置了根据不同profile推送到不同的docker服务器中的相关配置。 ## 技术选型 * 主体框架:spring + springmvc + mybatis * 关系型数据库: Mysql、SqlServer、oracle * 时序数据库: iotDB * 缓存数据库: redis * 安全框架: shiro * 日志框架:log-back * 消息中间件:EMQ ## 安装教程 1. 克隆master分支的代码到本地并将环境处理好。 2. 使用工程中的数据库初始脚本初始化数据库。 2. 修改数据库连接到你的数据库链接。 3. 尝试启动项目 ## 使用说明 1. 框架中只包含后端代码、测试时推荐试用postman。首先请求登录接口获取验证码,然后再通过验证码请求其他接口。 2. 为了方便测试和开发,在Constant类中设置了dev_mode变量。当dev_mode=true时框架的所有权限校验将会失效。想要更快速的体验框架可将该参数设为true,实际运行项目时需要将其设置为false。 3. 在项目的resources/download下有数据库的初始脚本,在正式测试前请先将数据库导好然后修改application.properties中的数据库链接。 ## 简单开发步骤 ### 基础业务代码 一. 创建与数据库对应的实体。此处以用户表作为例子进行演示。实体在本框架中起着非常重要的作用,很多的功能的都是以实现实体注解的方式来进行的。现将主要的注解说明如下: + @Dbinfo 用这个注解描述实体与注解的关系 + @PrimaryKey 这个注解描述实体中的哪个字段是主键字段。 + @Exist 校验类代码注解,验证是否有引用该条记录的别表的数据记录 + @Uniqueness 校验类代码注解,验证该字段的值在数据库中是否唯一 + @Foreign 校验类代码注解,验证将插入或者更新的值在数据库中是否在存在 + @FillField 外键关联注解,通过它控制生成连表查SQL ``` package test; import com.leenmvc.core.annotation.DbInfo; import com.leenmvc.core.annotation.FillField; import com.leenmvc.core.annotation.PrimaryKey; import com.leenmvc.core.annotation.TableField; import com.leenmvc.core.annotation.validator.Exist; import com.leenmvc.core.annotation.validator.Uniqueness; import com.leenmvc.core.annotation.validator.ValueIn; import com.leenmvc.core.annotation.validator.groups.AddGroup; import com.leenmvc.core.annotation.validator.groups.UpdateGroup; import com.leenmvc.core.base.BaseEntity; import com.leenmvc.core.enums.FillType; import com.leenmvc.core.security.dao.core.SysRoleUserDao; import com.leenmvc.core.security.entity.export.SysUserExcel; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import java.io.Serializable; import java.util.Date; import java.util.Set; @DbInfo(value = "sys_user", comment = "用户", excelEntity = SysUserExcel.class) public class SysUser extends BaseEntity { @PrimaryKey @Exist(classes = {SysRoleUserDao.class}, fields = {"userId"}) private Long id; /** * 用户名 */ @Uniqueness(message = "用户名重复,请换一个用户名", groups = {AddGroup.class, UpdateGroup.class}) @NotBlank(message = "用户名不能为空", groups = {AddGroup.class}) @Pattern(regexp = "^[a-zA-Z0-9]{4,16}$", message = "用户名只能是数字或字母", groups ={AddGroup.class,UpdateGroup.class} ) private String username; /** * 部门名称 */ @TableField(false) @FillField(entity = SysDept.class, outField = "name", inField = "deptId") private String deptName; @TableField(false) @FillField(type = FillType.ONE_TO_ONE, entity = SysDept.class, inField = "deptId") private SysDept dept; /*****/ // get、set方法 /*****/ } ``` 二. 创建与实体对应的Dao文件。 ``` package com.leenmvc.core.security.dao.core; import com.leenmvc.core.base.BaseBusinessDao; import com.leenmvc.core.security.entity.core.SysUserToken; import org.springframework.stereotype.Repository; /** * Dao层文件大多数情况下就是继承BaseBusinessDao<实体名>的一个 空文件 * 当存在特别频繁使用并且有一些逻辑处理的时候可以在类体内创建相关的方法 * */ @Repository public class SysUserDao extends BaseBusinessDao { } ``` 三. 创建与实体对应的Service文件。 + @TransactionMulti 这个注解是自实现的用于分布式事务控制的注解,同大多数mvc框架一样,需要作事务控制的业务都需要写在Service层中。 ``` package com.leenmvc.core.security.service.core; import com.leenmvc.core.annotation.TransactionMulti; import com.leenmvc.core.annotation.validator.groups.AddGroup; import com.leenmvc.core.base.BaseService; import com.leenmvc.core.exception.BusinessException; import com.leenmvc.core.security.TokenGenerator; import com.leenmvc.core.security.User; import com.leenmvc.core.security.dao.core.SysUserDao; import com.leenmvc.core.security.dao.core.SysUserTokenDao; import com.leenmvc.core.security.entity.core.SysUser; import com.leenmvc.core.security.entity.core.SysUserToken; import com.leenmvc.core.utils.security.PasswordUtils; import com.leenmvc.core.utils.thread.ThreadLocalManager; import com.leenmvc.core.utils.validator.ValidatorUtils; import org.joda.time.DateTime; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Date; /** * 用户服务层 */ @Service public class SysUserService extends BaseService { @Autowired private SysUserTokenDao sysUserTokenDao; @Autowired private SysUserDao sysUserDao; /** * 登录逻辑 * * @param user * @return */ public String login(SysUser user) { } /** * 登出操作 */ @TransactionMulti public void loginOut() { SysUserToken token = User.getToken(); Date date = new Date(); token.setExpireDate(date); if (!sysUserTokenDao.update(token)) { throw new BusinessException("登出失败!"); } else { ThreadLocalManager.put("loginOutStatus", 1); } } } ``` 四. 创建与实体对应的Controller文件。 + @Note 这个注解是用于规范接口说明的,框架强制规定需要在每个接口方法中使用该注解对接口的作用进行说明 ``` package com.leenmvc.core.web.controller; import com.leenmvc.core.annotation.Note; import com.leenmvc.core.base.BaseController; import com.leenmvc.core.dao.communal.Wrapper; import com.leenmvc.core.security.User; import com.leenmvc.core.security.entity.core.SysUser; import com.leenmvc.core.base.result.Result; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.Map; /** * 用户控制器类 * 用户的增删改查 * 用户权限的控制 */ @RestController @RequestMapping("system/sysUser") public class SysUserController extends BaseController { /** * 排除自己,的所有用户 */ @GetMapping("getUserList") @Note("查询除当前用户外所有用户,查询条件AL_realName") public Result getUserList(@RequestParam Map params){ Wrapper queryWrapper = getQueryWrapper(params); queryWrapper.uEq("id", User.getId()); List query = query(queryWrapper); return new Result().ok(query); } /** * 排除自己,的所有用户 */ @GetMapping("testEmpty") @Note("用于测试框架性能,在业务为空的情况下的并发数") public String testEmpty(){ return "ok"; } } ``` 五. 书写测试代码。 + 快速测试 1. 先确定Constant.java类中的dev_mode设置为真。 ``` // 开发者模式,所有的权限失效 public final static boolean dev_mode = true; ``` 2. 在浏览器中输入链接地址 + system/sysUser/getUserList + system/sysUser/testEmpty 3. 多说一句,在框架中实现了很多公共接口,只要本步骤中的实体、Dao、Service创建完成就可以直接通过公共接口直接获取相当部分的业务数据。现例举几个如下: + system/sysUser/getAll (获取全部) + system/sysUser/getById (根据ID获取) + system/sysUser/page (获取分页信息) + system/sysUser (post请求,增加记录) + system/sysUser (Put请求,修改记录) + system/sysUser (Delete请求,删除记录) + 常规测试 1. 先确定Constant.java类中的dev_mode设置为假。 ``` // 开发者模式,所有的权限失效 public final static boolean dev_mode = false; ``` 2. 请求验证码接口(具体参数可查看源码) ``` http://localhost:80/captcha?uuid=2123 ``` 3. 请求登录接口(具体的参数可查看源码) ``` http://localhost:80/loginUser ``` ## 参与贡献 1. 在Gitee或者Github上fork项目到自己的repo 2. 把fork过去的项目也就是你的项目clone到你的本地 3. 修改代码(记得一定要修改v1-dev分支) 4. commit后push到自己的库(v1-dev分支) 5. 登录Gitee或Github在你首页可以看到一个 pull request 按钮,点击它,填写一些说明信息,然后提交即可。 6. 等待维护者合并