SpringBoot项目快速开发框架JeecgBoot——Web处理!
发布时间:2025-06-26 20:17 浏览量:2
Jeecg Boot框架主要用于Web开发领域。下面介绍Jeecg Boot在Web开发中的常用功能,如控制器、登录、系统菜单、权限模块的角色管理和用户管理。
首先启动后台项目,将其导入IDEA中,并利用Maven自动加载依赖。然后把数据库脚本jeecg-boot目录下的db/jeecgboot-mysql-5.7.sql导入本地数据库中,并修改数据库的配置文件为本地配置。最后启动本地Redis服务,最后启动后台项目,请务必按顺序启动,否则会报错。
启动前端项目时,首先需要在本地安装并配置好Node.js,然后切换到前端代码目录ant-design-jeecg-vue下,在控制台使用npm install -y yarn命令安装yarn,并使用yarn install命令下载依赖,最后使用yarn run serve命令启动前端项目,或者可以先使用yarn run build命令编译项目后再启动。
启动前后端项目之后,在浏览器中访问http://localhost:3000/,可以看到登录页面,使用账号admin和密码123456登录,可以看到系统首页,如图8.4所示。访问http://localhost:8080/jeecg-boot/,可以查看系统的所有接口文档。
图8.4 系统首页
Jeecg Boot的控制器全部保存在包org.jeecg.modules.system.controller下,其中有一个是CommonController.java,它是文件上传下载的统一入口方法。在每个控制器上都有以下注解:
@Slf4j
@RestController
@RequestMapping("/sys/common")
以上3个注解的作用分别是记录日志、标记本类为控制器、设置请求的路径。控制器的返回值为固定格式,它返回Result类的实例对象。使用Result类能够非常快速地构建返回结果的对象。Result类的部分代码如下:
package org.jeecg.common.api.vo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.jeecg.common.constant.CommonConstant;
import java.io.Serializable;
/**
* 接口返回数据格式
* @author scott
* @email jeecgos@163.com
* @date 2019年1月19日
*/
@Data@ApiModel(value="接口返回对象", description="接口返回对象")
public class Resultimplements Serializable {/**
* 成功标志
*/
@ApiModelProperty(value = "成功标志")
private boolean success = true;
/**
* 返回处理消息
*/
@ApiModelProperty(value = "返回处理消息")
private String message = "操作成功!";
/**
* 返回代码
*/
@ApiModelProperty(value = "返回代码")
private Integer code = 0;
/**
* 返回数据对象data
*/
@ApiModelProperty(value = "返回数据对象")
private T result;
/**
* 时间戳
*/
@ApiModelProperty(value = "时间戳")
private long timestamp = System.currentTimeMillis;
public Result {
}
public Resultsuccess(String message) {this.message = message;
this.code = CommonConstant.SC_OK_200;
this.success = true;
return this; }
@Deprecated
Resultr = new Result;r.setSuccess(true);
r.setCode(CommonConstant.SC_OK_200);
r.setMessage("成功");
return r;
}
public staticResultOK {
Resultr = new Result;
public staticResultOK(T data) {
Resultr = new Result;
r.setSuccess(true);
r.setCode(CommonConstant.SC_OK_200);
r.setResult(data);
return r;
}
public staticResultOK(String msg, T data) {
Resultr = new Result;
r.setSuccess(true);
r.setCode(CommonConstant.SC_OK_200);
r.setMessage(msg);
r.setResult(data);
return r;
}
public staticResulterror(String msg, T data) {
Resultr = new Result;
r.setSuccess(false);
r.setCode(CommonConstant.SC_INTERNAL_SERVER_ERROR_500);
r.setMessage(msg); r.setResult(data);
return r;
}
public static Result error(String msg) {return error(CommonConstant.SC_INTERNAL_SERVER_ERROR_500, msg);
}
Result;r.setCode(code);
r.setMessage(msg);
r.setSuccess(false);
return r;
}
public Resulterror500(String message) {this.message = message;
this.code = CommonConstant.SC_INTERNAL_SERVER_ERROR_500;
this.success = false;
return this;
}
/**
* 无权限访问返回结果
*/
noauth(String msg) {return error(CommonConstant.SC_JEECG_NO_AUTHZ, msg);
}
@JsonIgnore
private String onlTable;
}
返回结果全部都使用Result进行包装后再返回,前端有统一的返回格式对结果进行处理。
在Jeecg Boot项目中,登录控制器的类是LoginController,该类包含所有的登录控制方法,包括登录、退出、获取访问量、获取登录人的信息、选择用户当前部门、短信API登录接口、手机号登录接口、获取加密字符串、后台生成图形验证码、App登录和图形验证码入口等。登录用到的相关数据库用户的表为sys_user。
下面详细说明登录方法的代码逻辑。其中,Controller登录方法的代码如下:
@ApiOperation("登录接口")
@RequestMapping(value = "/login", method = RequestMethod.POST)
public Resultlogin(@RequestBody SysLoginModelsysLoginModel){
Result;String username = sysLoginModel.getUsername;
String password = sysLoginModel.getPassword;
//update-begin--Author:scott Date:20190805 for:暂时注释掉密码加密逻
辑,
目前存在一些问题
//前端进行密码加密,后端进行密码解密
//password = AesEncryptUtil.desEncrypt(sysLoginModel.getPassword.
replaceAll("+", "\\+")).trim; //密码解密
辑,
目前存在一些问题
//update-begin-author:taoyan date:20190828 for:校验验证码
String captcha = sysLoginModel.getCaptcha;
if(captcha==null){
result.error500("验证码无效");
return result;
}
String lowerCaseCaptcha = captcha.toLowerCase;
String realKey =
MD5Util.MD5Encode(lowerCaseCaptcha+sysLoginModel.getCheckKey, "utf-
8");
Object checkCode = redisUtil.get(realKey); //当进入登录页面时,有一定概率出现验证码错误
if(checkCode==null ||
!checkCode.toString.equals(lowerCaseCaptcha)) {
result.error500("验证码错误");
return result;
}
//update-end-author:taoyan date:20190828 for:校验验证码
//1. 校验用户是否有效
LambdaQueryWrapperqueryWrapper = new LambdaQueryWrapper;
queryWrapper.eq(SysUser::getUsername,username);
SysUser sysUser = sysUserService.getOne(queryWrapper);
result = sysUserService.checkUserIsEffective(sysUser);
if(!result.isSuccess) {
return result;
}
//2. 校验用户名和密码是否正确
String userpassword = PasswordUtil.encrypt(username, password,
sysUser.getSalt);
String syspassword = sysUser.getPassword;
if (!syspassword.equals(userpassword)) {
result.error500("用户名或密码错误");
return result;
}
//用户登录信息
userInfo(sysUser, result);
//update-begin--Author:liusq Date:20210126 for:登录成功,删除Redis
中的验证码
redisUtil.del(realKey);
中的验证码
LoginUser loginUser = new LoginUser;
BeanUtils.copyProperties(sysUser, loginUser);
baseCommonService.addLog("用户名: " + username + ",登录成功!",
CommonConstant.LOG_TYPE_1, null,loginUser);
//update-end--Author:wangshuai Date:20200714 for:登录日志没有记
录人员 return result;
}
调用sysUserService的checkUserIsEffective方法,代码如下:
/**
* 校验用户是否有效
* @param sysUser
* @return
*/
@Override
public Result checkUserIsEffective(SysUser sysUser) {
Result result = new Result;//情况1:根据用户信息查询,该用户不存在
if (sysUser == null) {
result.error500("该用户不存在,请注册");
baseCommonService.addLog("用户登录失败,用户不存在!",
CommonConstant.
LOG_TYPE_1, null);
return result;
}
//情况2:根据用户信息查询,该用户已注销
//update-begin---author:王帅 if条件永远为false
if (CommonConstant.DEL_FLAG_1.equals(sysUser.getDelFlag)) {
//update-end---author:王帅 if条件永远为false
baseCommonService.addLog("用户登录失败,用户名:" +
sysUser.getUsername
+ "已注销!", CommonConstant.LOG_TYPE_1, null);
result.error500("该用户已注销");
return result;
}
//情况3:根据用户信息查询,该用户已冻结
if (CommonConstant.USER_FREEZE.equals(sysUser.getStatus)) {
+ "已冻结!", CommonConstant.LOG_TYPE_1, null);
result.error500("该用户已冻结");
return result; }
return result;
}
Controller的login方法用于判断用户登录是否成功,其执行逻辑如下:
(1)判断验证码是否正确。
(2)调用sysUserService的checkUserIsEffective方法查询当前用户是否存在,用户状态是否正常,确认用户没有注销和被冻结。
(3)校验用户名和密码是否正确。
(4)完善登录成功的用户信息。
(5)记录日志。
(6)返回登录成功的结果。
在网页上可以快速进行菜单的创建和查看,在“系统管理”|“菜单管理”菜单下,可以看到系统的所有菜单,并且可以新建一个菜单。新建菜单的页面如图8.5所示,系统菜单的控制器为SysPermissionController,数据库对应的表为sys_permission。
SysPermissionController类的部分方法如下:
/**
*
* 菜单权限表的前端控制器
*
*
* @Author scott
* @since 2018-12-21
*/
@Slf4j
@RestController
@RequestMapping("/sys/permission")
public class SysPermissionController { @Autowired
private ISysPermissionService sysPermissionService;
/**
* 加载数据节点
*
* @return
*/
@RequestMapping(value = "/list", method = RequestMethod.GET)
public Result> list {long start = System.currentTimeMillis;
Result> result = new Result;try {
LambdaQueryWrapperquery = new
LambdaQueryWrapper;
query.eq(SysPermission::getDelFlag,
CommonConstant.DEL_FLAG_0);
query.orderByAsc(SysPermission::getSortNo);
Listlist = sysPermissionService.list(query);treeList = new ArrayList;getTreeList(treeList, list, null);
result.setResult(treeList);
result.setSuccess(true);
log.info("======获取全部菜单数据=====耗时:" +
(System.currentTimeMillis - start) + "毫秒");
} catch (Exception e) {
log.error(e.getMessage, e);
}
return result;
}
/**
* 添加菜单
* @param permission
* @return
*/
//@RequiresRoles({ "admin" })
@RequestMapping(value = "/add", method = RequestMethod.POST)
public Resultadd(@RequestBody SysPermissionresult = new Result;try {
permission =
PermissionDataUtil.intelligentProcessData(permission);
sysPermissionService.addPermission(permission);
result.success("添加成功!");
} catch (Exception e) {
log.error(e.getMessage, e);
result.error500("操作失败");
}
return result;
}
}
以上为菜单列表和新建菜单的Controller,其对应新增菜单的service代码如下:
@Override
@CacheEvict(value =
CacheConstant.SYS_DATA_PERMISSIONS_CACHE,allEntries=
true)
public void addPermission(SysPermission sysPermission) throws
JeecgBoot
Exception {
//
-
//判断是否是一级菜单,如果是,则清空父菜单
if(CommonConstant.MENU_TYPE_0.equals(sysPermission.getMenuType))
{
sysPermission.setParentId(null);
}
-
String pid = sysPermission.getParentId;
if(oConvertUtils.isNotEmpty(pid)) {
//设置父节点不为子节点
this.sysPermissionMapper.setMenuLeaf(pid, 0); }
sysPermission.setCreateTime(new Date);
sysPermission.setDelFlag(0);
sysPermission.setLeaf(true);
this.save(sysPermission);
}
对应Dao方法的代码如下:
/**
* 修改菜单状态字段: 是否子节点
*/
@Update("update sys_permission set is_leaf=#{leaf} where id = #{id}")
public int setMenuLeaf(@Param("id") String id,@Param("leaf") int
leaf);
保存一个新的菜单时应判断是否是一级菜单,如果是,则清空父菜单,否则直接将菜单拼接到父菜单之下。
角色是系统权限管理的一部分,用来管理一部分权限的合集。JeecgBoot的角色管理功能是在“系统管理”|“角色管理”菜单下。创建一个新的角色,如图8.6所示,这里创建了一个临时工的角色。在角色管理中还可以查看有多少用户拥有该角色。
角色管理的入口控制器是SysRoleController,其部分源码如下:
/**
*
* 角色表的前端控制器
*
*
* @Author scott
* @since 2018-12-19
*/
@RestController
@RequestMapping("/sys/role")
@Slf4j
public class SysRoleController {
@Autowired
private ISysRoleService sysRoleService;
/**
* 分页列表查询
* @param role
* @param pageNo
* @param pageSize
* @param req
* @return */
@RequestMapping(value = "/list", method = RequestMethod.GET)
public Result> queryPageList(SysRole role,@RequestParam(name="pageNo", defaultValue="1")
Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10")
Integer
pageSize,
HttpServletRequest req) {
ResultQueryWrapperqueryWrapper = QueryGenerator.initQueryWrapper(role, req.getParameterMap);
Pagepage = new PageIPagepageList = sysRoleService.page(page,queryWrapper);
result.setSuccess(true);
result.setResult(pageList);
return result;
}
/**
* 添加
* @param role
* @return
*/
@RequestMapping(value = "/add", method = RequestMethod.POST)
//@RequiresRoles({"admin"})
public Resultadd(@RequestBody SysRole role) {Result;try {
role.setCreateTime(new Date);
sysRoleService.save(role);
result.success("添加成功!");
} catch (Exception e) {
log.error(e.getMessage, e);
result.error500("操作失败");
}
return result;
}
}
角色的列表查询和新建都使用MyBatisPlus的接口方法实现,在开发中不需要再次实现,从而更加快捷地完成功能开发。
当前登录的用户是管理员,系统还内置了其他账户。在sys_user表中,使用“系统管理”|“用户管理”命令可以查看所有的用户。下面新建一个账号为cc的新用户,然后登录。新建用户的设置页面如图8.7所示。
退出当前用户账号,使用cc登录,登录成功后的页面如图8.8所示。可以看到,已经登录成功,但是因为当前用户未分配任何权限,所以是空白页。
用户管理的入口控制器Controller是SysUserController,其部分源码如下:
/**
*
* 用户表的前端控制器
*
*/
@Slf4j
@RestController
@RequestMapping("/sys/user")
public class SysUserController {
@Autowired
private ISysBaseAPI sysBaseAPI;
@Autowired
private ISysUserService sysUserService;
/**
* 获取用户列表数据
* @param user
* @param pageNo
* @param pageSize
* @param req
* @return
*/
@PermissionData(pageComponent = "system/UserList") @RequestMapping(value = "/list", method = RequestMethod.GET)
public Result> queryPageList(SysUseruser,@RequestParam
(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer
pageSize,
HttpServletRequest req) {
ResultQueryWrapperqueryWrapper =QueryGenerator.initQueryWrapper
(user, req.getParameterMap);
// 外部模拟登录临时账号,不显示列表
queryWrapper.ne("username","_reserve_user_external");
Pagepage = new PageIPagepageList = sysUserService.page(page,queryWrapper);
//批量查询用户的所属部门
//步骤1:先获取全部的userIds
//步骤2:通过userIds一次性查询用户所属部门的名称
ListpageList.getRecords.stream.map(SysUser::
getId).collect(Collectors.toList);
if(userIds!=null && userIds.size>0){
MapuseDepNames =sysUserService.getDepNamesByUserIds(userIds);
pageList.getRecords.forEach(item->{
item.setOrgCodeTxt(useDepNames.get(item.getId));
});
}
result.setSuccess(true);
result.setResult(pageList);
log.info(pageList.toString);
return result;
}
//@RequiresRoles({"admin"})
//@RequiresPermissions("user:add")
@RequestMapping(value = "/add", method = RequestMethod.POST)
public Resultadd(@RequestBody JSONObject jsonObject) {Result; String selectedRoles = jsonObject.getString("selectedroles");String selectedDeparts = jsonObject.getString("selecteddeparts");
try {
SysUser user = JSON.parseObject(jsonObject.toJSONString,
SysUser.class);
user.setCreateTime(new Date); //设置创建时间
String salt = oConvertUtils.randomGen(8);
user.setSalt(salt);
String passwordEncode =
PasswordUtil.encrypt(user.getUsername,user.getPassword, salt);
user.setPassword(passwordEncode);
user.setStatus(1);
user.setDelFlag(CommonConstant.DEL_FLAG_0);
// 在一个方法中使用事务保存用户信息
sysUserService.saveUser(user, selectedRoles, selectedDeparts);
result.success("添加成功!");
} catch (Exception e) {
log.error(e.getMessage, e);
result.error500("操作失败");
}
return result;
}
}
这里节选了用户列表和新增用户入口的方法。查询用户列表的service实现代码节选如下:
@Override
public Mapthis.baseMapper.getDepNamesByUserIds(userIds);
Map;list.forEach(item -> {
if (res.get(item.getUserId) == null) {
res.put(item.getUserId, item.getDepartName); } else {
res.put(item.getUserId, res.get(item.getUserId) +
"," +
item.getDepartName);
}
}
);
return res;
}
其中,调用Dao的代码如下:
/**
* 根据 userIds查询,查询用户所属部门的名称(多个部门名称用逗号隔开)
* @param
* @return
*/
public MapgetDepNamesByUserIds(ListXML中的SQL语句如下:
新增用户的service代码如下:@Override
@Transactional(rollbackFor = Exception.class)
public void saveUser(SysUser user, String selectedRoles, String
selected
Departs) {
//步骤1 保存用户
this.save(user);
//步骤2 保存角色
if(oConvertUtils.isNotEmpty(selectedRoles)) {
String arr = selectedRoles.split(",");
for (String roleId : arr) {
SysUserRole userRole = new SysUserRole(user.getId, roleId);
sysUserRoleMapper.insert(userRole);
}
}
//步骤3 保存所属部门
if(oConvertUtils.isNotEmpty(selectedDeparts)) {
String arr = selectedDeparts.split(",");
for (String deaprtId : arr) {
SysUserDepart userDeaprt = new SysUserDepart(user.getId,
deaprtId);
sysUserDepartMapper.insert(userDeaprt);
}
}
}
保存用户时附带保存用户角色和用户所属部门的数据。在方法中增加了事务,以确保数据保存的完整性。
package org.jeecg.common.exception;
/**
* 异常处理器
*
* @Author scott
* @Date 2019
*/
@RestControllerAdvice
@SLF4J
public class JeecgBootExceptionHandler {
/**
* 处理自定义异常
*/
@ExceptionHandler(JeecgBootException.class)
public Result handleRRException(JeecgBootException e){
log.error(e.getMessage, e);
return Result.error(e.getMessage);
}
@ExceptionHandler(NoHandlerFoundException.class)
public Result handlerNoFoundException(Exception e) {
log.error(e.getMessage, e);
return Result.error(404, "路径不存在,请检查路径是否正确");
}
@ExceptionHandler({UnauthorizedException.class,
AuthorizationException.class})
public Result handleAuthorizationException(AuthorizationException
e){
log.error(e.getMessage, e);
return Result.noauth("没有权限,请联系管理员授权");
}
@ExceptionHandler(Exception.class)
public Result handleException(Exception e){ log.error(e.getMessage, e);
return Result.error("操作失败,"+e.getMessage);
}
/**
* Spring默认上传文件的大小为10MB,若超出则捕获异常MaxUploadSizeExceeded
Exception
*/
@ExceptionHandler(MaxUploadSizeExceededException.class)
public Result handleMaxUploadSizeExceededException(MaxUploadSize
ExceededException e) {
log.error(e.getMessage, e);
return Result.error("文件超出10MB的限制,请压缩或降低文件质量! ");
}
@ExceptionHandler(PoolException.class)
public Result handlePoolException(PoolException e) {
log.error(e.getMessage, e);
return Result.error("Redis 连接异常!");
}
}
以上列举的只是Jeecg Boot的一部分功能,还有很多功能读者可以自行去挖掘。常见的功能如下:
统计报表功能:使用该功能后,现有的报表就不再需要重新构建报表页面,而只需要后端返回响应的数据就能看到与结果相符的报表。
在线开发功能:使用该功能可以非常快速地开发在线表单,并且可以设置参数校验的规则,从而对系统的数据源进行管理。
还有动态切换数据源和代码生成等功能读者可以自行演示。
说明:如果现有功能不能满足用户的业务需要,就需要用户自己完成开发。
如果在使用的过程中发现系统Bug,则可以向Jeecg Boot团队反馈,也可以提供建议,这样也为开源做出了自己的贡献。