网站首页 编程语言 正文
目录
一. 开发公共模块,数据封装和全局异常处理及application.properties
编辑
二. 开发登陆要用的接收前端数据的dto,和封装查询结果的model
三. 开发登陆的控制层
四. 开发存储当前用户的model和常量类
五. 开发登陆的业务类
六. 开发持久化组件
七. 开发登录前端(vue+ajax)
八. 动态菜单的开发
8.1 首先看数据库查出来的数据
8.2 定义封装查询结果的model
8.3 定义封装树状菜单结构的bean
8.4 开发控制层
8.5 开发业务层
8.6 开发持久层
8.7 编写映射文件
8.8 编写前端
一. 开发公共模块,数据封装和全局异常处理及application.properties
package com.xupt.ygq.oa.common;
public class Result<T> {
public static final int CODE_OK = 200;
public static final int CODE_ERR_BUSINESS = 500;
public static final int CODE_ERR_SYS = 530;
public static final int CODE_ERR_UNLOGINED = 520;
public static <T>Result<T> ok(){
return new Result(true,CODE_OK,null,null);
}
public static <T>Result<T> ok(String message){
return new Result(true,CODE_OK,message,null);
}
public static <T>Result<T> ok(T data){
return new Result(true,CODE_OK,null,data);
}
public static <T>Result<T> ok(String message,T data){
return new Result(true,CODE_OK,message,data);
}
public static <T>Result<T> err(int errCode ,String message){
return new Result(false,errCode,message,null);
}
public static <T>Result<T> err(int errCode ,String message,T data){
return new Result(false,errCode,message,data);
}
private boolean success;//是否成功
private int code;//200 成功 500 业务失败,530 系统错误,520 未登录
private String message;//概要信息
private T data;
public Result(boolean success, int code, String message, T data) {
this.success = success;
this.code = code;
this.message = message;
this.data = data;
}
public boolean isSuccess() {
return success;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public T getData() {
return data;
}
}
import com.xupt.ygq.oa.exception.BusinessException;
import com.xupt.ygq.oa.exception.SysException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.TypeMismatchException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Slf4j
@RestControllerAdvice//该注解说明本类是一个RestController的拦截器,
// 还可以对controller处理方法添加额外逻辑,做增强处理
public class DemoControllerAdvice {
//该注解说明本方法是一个异常处理器,即当被拦截的controller处理方法发生指定的异常时,即由本方法处理
@ExceptionHandler(ConstraintViolationException.class)
public Result handleConstraintViolationException(ConstraintViolationException e){
log.error("参数不匹配",e);
Set<ConstraintViolation<?>> set = e.getConstraintViolations();//获取验证错误集合
//将验证错误集合中,每一个错误的信息取出来,组成一个新的集合,再将新集合中的元素用”,“连接成一个字符串,返回这个字符串
String msg = set.stream().map(item->item.getMessage()).collect(Collectors.joining(","));
msg.substring(0,msg.length()-1);
return Result.err(Result.CODE_ERR_SYS,msg);
}
//邦json没绑好异常(post请求)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e){
log.error("参数不匹配",e);
//获取参数绑定结果(包括绑定错误信息)
BindingResult bindingResult = e.getBindingResult();
//获取属性错误集合
List<FieldError> fieldErrorList = bindingResult.getFieldErrors();
String errMsg = fieldErrorList.stream()
.map(fieldError->fieldError.getField()+":"+fieldError.getDefaultMessage())
.collect(Collectors.joining(","));
return Result.err(Result.CODE_ERR_SYS,errMsg);
}
//绑普通字符串没绑好异常
@ExceptionHandler(BindException.class)
public Result handleBindException(BindException e){
log.error("参数不匹配",e);
//获取参数绑定结果(包括绑定错误信息)
BindingResult bindingResult = e.getBindingResult();
//获取属性错误集合
List<FieldError> fieldErrorList = bindingResult.getFieldErrors();
String errMsg = fieldErrorList.stream()
.map(fieldError->fieldError.getField()+":"+fieldError.getDefaultMessage())
.collect(Collectors.joining(","));
return Result.err(Result.CODE_ERR_SYS,errMsg);
}
//处理自定义系统异常
@ExceptionHandler(SysException.class)
public Result handleSysException(SysException e){
log.error("系统错误",e);
return Result.err(Result.CODE_ERR_SYS,"系统维护中");
}
//处理自定义业务异常
@ExceptionHandler(BusinessException.class)
public Result handleBusinessException(BusinessException e){
return Result.err(Result.CODE_ERR_BUSINESS,e.getMessage());
}
//参数格式异常
@ExceptionHandler(TypeMismatchException.class)
public Result handleTypeMismatchException(TypeMismatchException e){
log.error("系统错误",e);
return Result.err(Result.CODE_ERR_BUSINESS,"系统维护中");
}
//处理遗留的异常
@ExceptionHandler(Exception.class)
public Result handleException(Exception e){
log.error("系统错误",e);
return Result.err(Result.CODE_ERR_BUSINESS,"系统维护中");
}
}
二. 开发登陆要用的接收前端数据的dto,和封装查询结果的model
public class User {
private String u_id;
private String u_name;
private String u_pwd;
public String getU_id() {
return u_id;
}
public void setU_id(String u_id) {
this.u_id = u_id;
}
public String getU_name() {
return u_name;
}
public void setU_name(String u_name) {
this.u_name = u_name;
}
public String getU_pwd() {
return u_pwd;
}
public void setU_pwd(String u_pwd) {
this.u_pwd = u_pwd;
}
}
import javax.validation.constraints.NotEmpty;
public class LoginDto {
//@NotEmpty仅针对String ,集合等
@NotEmpty(message = "账号不得为空")
private String u_id;
@NotEmpty(message = "密码不得为空")
private String u_pwd;
public String getU_id() {
return u_id;
}
public void setU_id(String u_id) {
this.u_id = u_id;
}
public String getU_pwd() {
return u_pwd;
}
public void setU_pwd(String u_pwd) {
this.u_pwd = u_pwd;
}
}
dto里面加了数据验证,所以在作为参数接收前端传回来的数据的时候,前面要加@Validated注解
三. 开发登陆的控制层
import com.xupt.ygq.oa.common.Result;
import com.xupt.ygq.oa.common.page.CurrentUser;
import com.xupt.ygq.oa.common.page.OaConstants;
import com.xupt.ygq.oa.dto.LoginDto;
import com.xupt.ygq.oa.fun.security.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;
@RestController
@RequestMapping("/security/login")//为本控制器处理方法的所有映射地址加统一前缀
public class LoginController {
@Autowired
private LoginService loginService;
@PostMapping("")//此方法地址:/security/login
public Result login(@Validated @RequestBody LoginDto dto,HttpSession session){
CurrentUser currentUser = loginService.checkLogin(dto);
//当前用户信息存放在session中
session.setAttribute(OaConstants.SESSION_NAME_CURRENT_USER,currentUser);
return Result.ok();
}
}
六个注解:
①:@Restcontroller
②:@RequestMapping("+++") :为本控制器处理方法的所有映射地址统一加前缀
③:@Autowired
④:@PostMapping("") :此方法地址为项目根地址加上前面的前缀
⑤:@Validated:表示这个用来接收参数的javaBean里面添加了数据验证
⑥:@RequestBody:表示这个Post请求传递的是json串的请求体
一个对象:
CurrentUser:表示当前登录用户
一个重要参数:
session:用来把查到的当前登录用户存到session中,本次会话都可以访问的到
注意:session.setAttribute()存数据的时候,键用了一个常量来表示,可以避免后续使用出错
四. 开发存储当前用户的model和常量类
public class CurrentUser {
private String UserId;
private String UserName;
public String getUserId() {
return UserId;
}
public void setUserId(String userId) {
UserId = userId;
}
public String getUserName() {
return UserName;
}
public void setUserName(String userName) {
UserName = userName;
}
}
//常量类
public class OaConstants {
/*
* session中用于存放当前用户对象的属性名称
* */
public static final String SESSION_NAME_CURRENT_USER = "SESSION_NAME_CURRENT_USER";
}
五. 开发登陆的业务类
public interface LoginService {
//验证用户账号或密码是否正常,若正确返回表示当前用户的对象,否则抛出业务异常(BusinessException)
public CurrentUser checkLogin(LoginDto loginDto);
}
@Service
@Transactional
public class LoginServiceImpl implements LoginService {
@Autowired
private LoginDao loginDao;
@Override
public CurrentUser checkLogin(LoginDto dto) {
User user = loginDao.findUserByIdAndPwd(dto);
if (user == null ){
throw new BusinessException("账号或密码错误!!");
}
CurrentUser currentUser = new CurrentUser();
currentUser.setUserId(user.getU_id());
currentUser.setUserName(user.getU_name());
return currentUser;
}
}
业务实现类中:
两个注解:
①:@Service
②:@Transactional
要对当前有没有用户做出判断,没有的话抛出异常,到Controller里面再由专门处理异常的类去处理。有的话,把查到的用户(User)封装到当前用户(CurrentUser)里面。
六. 开发持久化组件
import com.xupt.ygq.oa.dto.LoginDto;
import com.xupt.ygq.oa.model.User;
import org.apache.ibatis.annotations.Select;
public interface LoginDao {
@Select("select u_id,u_name from t_user where u_id=#{u_id} and u_pwd=#{u_pwd}")
public User findUserByIdAndPwd(LoginDto dto);
}
七. 开发登录前端(vue+ajax)
<script>
//1.定义登陆数据
const loginData = {
u_id:'',//账号
u_pwd:''//密码
};
//2.定义登陆函数
const login = () =>{
//向服务端发送post请求,提交数据为loginData
//只有成功的情况下的success=true,同时code值为200时,才能执行then
ajax.post("/security/login",loginData).then(result=>{
//这里意味着成功
//then表示提示信息显示完成后在进行的动作
xTip.success('登陆成功').then(()=>{
window.location.href='home.html';
});
});
};
const cfg = {
setup() {
return {
//3.导出数据在页面上使用
loginData,
login,
};
}
};
Vue.createApp(cfg).use(XModal).use(XPagination).mount('#app');
</script>
<!-- 4. 将登录数据与账号框和密码框绑定 -->
<div class="form-floating">
<input type="text" class="form-control" placeholder="账号" v-model="loginData.u_id">
<label>账号:</label>
</div>
<div class="form-floating">
<input type="password" class="form-control" placeholder="密码" v-model="loginData.u_pwd">
<label>密码:</label>
</div>
<!-- 5. 在登录按钮上设置事件绑定函数login -->
<button class="w-100 btn btn-lg btn-primary" type="button" @click="login">登录</button>
八. 动态菜单的开发
8.1 首先看数据库查出来的数据
明显的p代表的是父菜单,f代表子菜单
8.2 定义封装查询结果的model
public class Fun {
private Integer p_id;
private String p_name;
private Integer f_id;
private String f_name;
private String f_url;
public Integer getP_id() {
return p_id;
}
public void setP_id(Integer p_id) {
this.p_id = p_id;
}
public String getP_name() {
return p_name;
}
public void setP_name(String p_name) {
this.p_name = p_name;
}
public Integer getF_id() {
return f_id;
}
public void setF_id(Integer f_id) {
this.f_id = f_id;
}
public String getF_name() {
return f_name;
}
public void setF_name(String f_name) {
this.f_name = f_name;
}
public String getF_url() {
return f_url;
}
public void setF_url(String f_url) {
this.f_url = f_url;
}
}
8.3 定义封装树状菜单结构的bean
//封装树状菜单结构的bean
public class MenuDto {
private Integer menuId;
private String menuName;
private String menuUrl;
//子菜单集合
private List<MenuDto> chidren;
public Integer getMenuId() {
return menuId;
}
public void setMenuId(Integer menuId) {
this.menuId = menuId;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getMenuUrl() {
return menuUrl;
}
public void setMenuUrl(String menuUrl) {
this.menuUrl = menuUrl;
}
public List<MenuDto> getChidren() {
return chidren;
}
public void setChidren(List<MenuDto> chidren) {
this.chidren = chidren;
}
}
8.4 开发控制层
@RestController
@RequestMapping("/security/home")
public class HomeController {
@Autowired
private HomeService homeService;
@GetMapping("/menu")
public Result<List<MenuDto>> userMenuList(HttpSession session){
//sesssion中取出来的数据都是object的
CurrentUser currentUser = (CurrentUser) session.getAttribute(OaConstants.SESSION_NAME_CURRENT_USER);
List<MenuDto> menuDtoList = homeService.getUserMenuList(currentUser.getUserId());
return Result.ok(menuDtoList);
}
}
数据是由用户id查出来的,所以需要从session中取出当前用户传给业务层。
8.5 开发业务层
import com.xupt.ygq.oa.dto.MenuDto;
import java.util.List;
public interface HomeService {
public List<MenuDto> getUserMenuList(String userId);
}
@Service
@Transactional
public class HomeServiceImpl implements HomeService {
@Autowired
private HomeDao homeDao;
@Override
public List<MenuDto> getUserMenuList(String userId) {
List<Fun> funList = homeDao.findUserFunList(userId);
//主菜单集合
List<MenuDto> mainList = new ArrayList<>();
MenuDto currentMainMenu = null;//当前主菜单
for (Fun fun:funList){
if (currentMainMenu == null || !fun.getP_id().equals(currentMainMenu.getMenuId())){
/*如果当前主菜单不存在,或者当前遍历的数据中的父菜单编号与当前主菜单编号不相符
应当新创建一个当前主菜单,并放入主菜单集合*/
currentMainMenu = new MenuDto();
currentMainMenu.setMenuId(fun.getP_id());//设置主菜单编号
currentMainMenu.setMenuName(fun.getP_name());//设置主菜单名称
currentMainMenu.setChidren(new ArrayList<MenuDto>());//设置子菜单集合
mainList.add(currentMainMenu);
}
//将当前遍历数据中的子菜单部分分离出来,封装到MenuDto对象中,并将该对象放入当前主菜单的子菜单集合中
MenuDto subMenu = new MenuDto();
subMenu.setMenuId(fun.getF_id());
subMenu.setMenuName(fun.getF_name());
subMenu.setMenuUrl(fun.getF_url());
currentMainMenu.getChidren().add(subMenu);
}
/*funList.forEach(fun->{
if (currentMainMenu == null || !fun.getP_id().equals(currentMainMenu.getMenuId())){
*//*
* 如果当前主菜单不存在,或者当前遍历的数据中的父菜单编号与当前主菜单编号不相符
* 应当新创建一个当前主菜单,并放入主菜单集合
* *//*
currentMainMenu = new MenuDto();//内部类不能访问外部的局部变量
}
});*/
return mainList;
}
}
业务类里面要把查询到的结果封装成MenuDto对象,再由控制器带着MenuDto返回给前端。
8.6 开发持久层
import com.xupt.ygq.oa.model.Fun;
import java.util.List;
public interface HomeDao {
public List<Fun> findUserFunList(String userId);
}
8.7 编写映射文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xupt.ygq.oa.fun.security.dao.HomeDao">
<select id="findUserFunList" resultType="com.xupt.ygq.oa.model.Fun">
select
p.f_id p_id,
p.f_name p_name,
c.f_id,
c.f_name,
c.f_url
from
t_fun c join t_fun p on c.f_pid = p.f_id
join t_rf rf on c.f_id = rf.f_id
join t_role r on rf.ro_id = r.ro_id
join t_ur ur on r.ro_id = ur.ro_id
where
c.f_ismenu = 1 and ur.u_id = #{userId}
</select>
</mapper>
8.8 编写前端
<script>
//1.定义菜单数据
const menuList = Vue.ref([]);
//2.定义获取菜单数据的函数
const getMenuList =()=>{
ajax.get('/security/home/menu').then(result=>{
menuList.value = result.data;
});
};
//3.执行获取菜单数据的函数
getMenuList();
const cfg = {
setup(){
return {
menuList,//4.导出菜单数据(在页面上使用)
};
}
};
Vue.createApp(cfg).use(XModal).use(XPagination).mount('#app');
</script>
<li v-for="main in menuList" class="mb-1">
<button class="btn btn-toggle align-items-center rounded collapsed" data-bs-toggle="collapse"
:data-bs-target=" '#main-' + main.menuId" aria-expanded="false">
{{main.menuName}}
</button>
<div class="collapse" :id=" 'main-' + main.menuId">
<ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
<li v-for="sub in main.chidren">
<a :href="sub.menuUrl" target="mainFrame" class="link-dark rounded">
{{sub.menuName}}
</a>
</li>
</ul>
</div>
</li>
原文链接:https://blog.csdn.net/weixin_45836787/article/details/125916798
相关推荐
- 2023-08-16 el-input输入框去除边框,且实现自动换行功能
- 2023-01-31 C#实现伪装文件夹功能_C#教程
- 2023-04-20 ES6:字符串的扩展及新增方法
- 2022-05-03 SQL Server查询某个字段在哪些表中存在_MsSql
- 2022-05-13 C++ OpenCV cv::Mat 矩阵操作
- 2023-02-10 解决Jupyter Notebook “signal only works in main thre
- 2024-01-29 理解并使用 XPath 中的 `normalize-space` 函数
- 2022-07-07 C++实现数组中元素组合出最大值_C 语言
- 最近更新
-
- window11 系统安装 yarn
- 超详细win安装深度学习环境2025年最新版(
- Linux 中运行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存储小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基础操作-- 运算符,流程控制 Flo
- 1. Int 和Integer 的区别,Jav
- spring @retryable不生效的一种
- Spring Security之认证信息的处理
- Spring Security之认证过滤器
- Spring Security概述快速入门
- Spring Security之配置体系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置权
- redisson分布式锁中waittime的设
- maven:解决release错误:Artif
- restTemplate使用总结
- Spring Security之安全异常处理
- MybatisPlus优雅实现加密?
- Spring ioc容器与Bean的生命周期。
- 【探索SpringCloud】服务发现-Nac
- Spring Security之基于HttpR
- Redis 底层数据结构-简单动态字符串(SD
- arthas操作spring被代理目标对象命令
- Spring中的单例模式应用详解
- 聊聊消息队列,发送消息的4种方式
- bootspring第三方资源配置管理
- GIT同步修改后的远程分支