SSM+vue踩坑之旅
项目运行图一览
1、登录页面
2、用户管理
本来想做分页的,感觉太麻烦了,用户的 CURD。
3、权限管理
不同用户分属不同用户组,不同用户组具有不同的功能权限,即旁边的功能栏。用户组和用户组权限的 CURD 。
test用户是学生用户组,只有三个权限。
功能1、功能2、用户资料页面都没做,只做了上面的练习练习。
前端Vue3
一、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
2、Mybatis配置
主要还是关于 SqlSessionFactoryBean 和 dataSource 的配置,事务用不用看具体项目。不过网上乱找很容易看的一头雾水,建议花时间把官方文档读读,会收获很多。
二、具体代码内容
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());
}
}