天天看點

SSM+vue踩坑之旅SSM+vue踩坑之旅

SSM+vue踩坑之旅

項目運作圖一覽

1、登入頁面

SSM+vue踩坑之旅SSM+vue踩坑之旅

2、使用者管理

本來想做分頁的,感覺太麻煩了,使用者的 CURD。

SSM+vue踩坑之旅SSM+vue踩坑之旅

3、權限管理

不同使用者分屬不同使用者組,不同使用者組具有不同的功能權限,即旁邊的功能欄。使用者組和使用者組權限的 CURD 。

SSM+vue踩坑之旅SSM+vue踩坑之旅

test使用者是學生使用者組,隻有三個權限。

SSM+vue踩坑之旅SSM+vue踩坑之旅

功能1、功能2、使用者資料頁面都沒做,隻做了上面的練習練習。

前端Vue3

vue項目代碼位址

一、axios

axios 用的 axios 與 vue-axios

import axios from './plugins/axios.js'
import VueAxios from 'vue-axios'

createApp(home)
  .use(VueAxios, axios)
           

1、剛開始關于請求 content-type 的三種常用資料格式都迷了半天

請求頭 說明 推薦後端接收方式
application/json 資料以json字元串的形式發送到後端 用@RequestBody Object obj接收,直接轉化為對象,最好傳過來的和對象中的屬性同名,不然需要自己再設定
application/x-www-form-urlencoded 以普通表單形式(鍵值對)發送到後端 用@RequestParam Map<Object,Object> map去解析接收,直接以鍵值對擷取資料
multipart/form-data 請求體的資料處理為一條消息,以标簽為單元,用分隔符分開。既可以上傳鍵值對,也可以上傳檔案。 須要使用post方式才可以請求到,所有的檔案和參數在HttpServletRequest中解析,比較麻煩,具體用到了再寫個類

還有關于 Parmas 就是在請求位址後面的 ?xxx=xxx&xx=xx 那部分

this.axios.get(url,
        data,   //表單資料
        {params: {xx:,xx:}}  //請求Parmas資料
    ).then((response) => {
        //請求成功
    }).catch(error => {
        //請求失敗
    })
 this.axios.delete(url, 
    { data: row }     //delete請求中的表單資料需要{}起來,put、post和get一樣
    ).then().catch()
           

2、axios的request、response攔截器

這個主要統一對 request 做一些處理,封裝一些内容,或者是對 response 響應結果狀态碼處理,我主要用來處理了 token 與響應碼簡單處理,網上搜一下就可以參考的很多。

我項目axios.js檔案的碼雲位址

二、router **

router 中也用了一個攔截,用來判斷進入的路由位址是否需要登入,需要登入的話跳轉。

router.beforeEach((to, from, next) => {
  // window.document.title=to.meta.title;
  if (to.meta.requireAuth === true) { // 需要登入權限進入的路由
    if (localStorage.getItem('token')) { // 取到登入token
      next()
    } else {
      next({ name: 'login' })
    }
  } else { // 不需要登入權限
    next()
  }
})
           

使用者驗證除了 token 還可以用 session 儲存使用者資訊(各有優劣)。前端vue的路由攔截,相當于之前後端渲染視圖中的 filter 過濾器驗證。

三、Element-plus

這個也遇到挺多坑的,不知道是vue3的問題還是啥,印象之前vue 2.x的時候沒這麼多莫名其妙的bug,也可能是我對vue3不熟悉,早知道還是用vue2.x了。踩坑的時候一度不想寫了,現在卻沒太大印象了,踩過一次就不感覺難了。。

關于前端web的大部分問題都可以在 https://developer.mozilla.org/zh-CN/ 這個網站上學到。

後端SSM

後端代碼位址

一、配置

**1、 XML 配置與 Java 配置對比 **

雖然我看網上教程和書本學的時候,大多都是用 xml 檔案配置的,但做這個的時候全是 java 配置,加深了對 spring 的了解。

web.xml檔案 與 extends AbstractAnnotationConfigDispatcherServletInitializer

主要是設定 spring 上下文,springmvc 容器等配置。

java代碼配置:

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};  //DispatcherServlet映射到 "/"
    }

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] {RootConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebConfig.class };     //指定配置類
    }
}
           
applicationContext.xml 與 RootConfig.class

Sprig bean 的注冊、生命周期管理。

java代碼配置:

@Configuration
@EnableTransactionManagement //開啟事務支援
@Import(DruidDataSourceConfig.class)//導入資料源的配置
@ComponentScan(basePackages = {"com.huel.dms"},
        excludeFilters = {
                @ComponentScan.Filter(type= FilterType.ANNOTATION,value = EnableWebMvc.class)
        })
public class RootConfig {
}
           

基本是隻寫了個包掃描,都注解到具體的代碼裡了。

springMVC.xml 與 WebConfig.java

springmvc 的相關配置,控制器、視圖解析、過濾器、攔截器等等一些。。。

java代碼配置:

@Configuration
@EnableWebMvc
@ComponentScan("com.huel.dms")
public class WebConfig implements WebMvcConfigurer {

    @Resource
    TokenInterceptor tokenInterceptor;
    @Resource
    LoginInterceptor loginInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {   
        registry.addInterceptor(tokenInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/login","/outTine");
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/login");
    }
}
           

隻注冊添加了兩個攔截器,一個攔截登入的控制器,一個攔截其它的。其它的也是掃描注解。

詳細的給大家分享一個 Spring Framework 中文文檔 5.1.3 RELEASE

Spring Framework 中文文檔

2、Mybatis配置

主要還是關于 SqlSessionFactoryBean 和 dataSource 的配置,事務用不用看具體項目。不過網上亂找很容易看的一頭霧水,建議花時間把官方文檔讀讀,會收獲很多。

mybatis 官方中文文檔

mybatis-spring 官方中文文檔

二、具體代碼内容

1、關于jwt

可以先看 阮一峰 的部落格了解下概念:JSON Web Token 入門教程

官網上有幾個不同的 java 輪子,大家挑個用就行 jwtio 網上還有很多篇這幾個對比的部落格。

SSM+vue踩坑之旅SSM+vue踩坑之旅

2、utils

nimbus-jose-jwt 的工具類,封裝好的 Response 相應結果類,Log4jUtil 的配置檔案,不過沒怎麼用,下個學spring boot的項目,一定要學着寫 doc 和 log

3、控制器、攔截器

控制器,主要就是資料的接收解析部分。

SSM+vue踩坑之旅SSM+vue踩坑之旅

然後注意在類上面加上 @CrossOrigin 跨域注解,方法不要加 @ResponseBody友善我們後邊在攔截器對 Response 處理。

@Component
@Slf4j
public class TokenInterceptor implements HandlerInterceptor {

    @Resource
    JwtUtil jwtUtil;

    public void printWriter(PrintWriter out,String str){
        out.write(str);       //放入response流
        out.flush();
        out.close();      //強制發送緩沖區資料,關閉流
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/javascript; charset=utf-8");   //設定編碼格式
        if (request.getMethod().equals("OPTIONS")) return true;
        response.setHeader("Access-Control-Expose-Headers", "token");
        String token = request.getHeader("token");
        if (null != token && !token.equals("")) {                 //token存在
            if (!jwtUtil.verifyToken(token) || !jwtUtil.verifyTime(token) ) {
                response.setHeader("token", null);   //逾時或者失效,設定為null
                printWriter(response.getWriter(),new Result<>(ResultStatus.Token_TIMEOUT).toJson());
                return false;
            }
            String num = jwtUtil.getAdu(token);
            request.setAttribute("num", num);
        }
        return true;  //繼續執行action
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView
            modelAndView) throws Exception {
        if (request.getMethod().equals("OPTIONS")) return;
        Result result = (Result) modelAndView.getModel().get("result");       //得到傳回結果
        String token = request.getHeader("token");
        if (null != token && !token.equals("")) {
            token = jwtUtil.updateToken(token);
            response.setHeader("token", token);
            response.setHeader("Access-Control-Expose-Headers", "token");
        }
        if(null == result)
            result = new Result(ResultStatus.Token_TIMEOUT);
        printWriter(response.getWriter(),result.toJson());
    }
}