SSM+vue踩坑之旅
項目運作圖一覽
1、登入頁面
2、使用者管理
本來想做分頁的,感覺太麻煩了,使用者的 CURD。
3、權限管理
不同使用者分屬不同使用者組,不同使用者組具有不同的功能權限,即旁邊的功能欄。使用者組和使用者組權限的 CURD 。
test使用者是學生使用者組,隻有三個權限。
功能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 網上還有很多篇這幾個對比的部落格。
2、utils
nimbus-jose-jwt 的工具類,封裝好的 Response 相應結果類,Log4jUtil 的配置檔案,不過沒怎麼用,下個學spring boot的項目,一定要學着寫 doc 和 log
3、控制器、攔截器
控制器,主要就是資料的接收解析部分。
然後注意在類上面加上 @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());
}
}