日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

springboot登陸前后端及動態菜單

作者:挽留自己的頭發 更新時間: 2022-07-22 編程語言

目錄

一. 開發公共模塊,數據封裝和全局異常處理及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

欄目分類
最近更新