JavaWeb 学习笔记
总体框架
web后端开发现在基本上都是基于标准的三层架构进行开发的,在三层架构当中,Controller控制器层负责接收请求响应数据,Service业务层负责具体的业务逻辑处理,而Dao数据访问层也叫持久层,就是用来处理数据访问操作的,来完成数据库当中数据的增删改查操作。
我们在学习这些web后端开发技术的时候,我们都是基于主流的SpringBoot进行整合使用的。而SpringBoot又是用来简化开发,提高开发效率的。像过滤器、拦截器、IOC、DI、AOP、事务管理等这些技术到底是哪个框架提供的核心功能?
- Filter过滤器、Cookie、 Session这些都是传统的JavaWeb提供的技术。
- JWT令牌、阿里云OSS对象存储服务,是现在企业项目中常见的一些解决方案。
- IOC控制反转、DI依赖注入、AOP面向切面编程、事务管理、全局异常处理、拦截器等,这些技术都是 Spring
Framework框架当中提供的核心功能。 - Mybatis就是一个持久层的框架,是用来操作数据库的。
在Spring框架的生态中,对web程序开发提供了很好的支持,如:全局异常处理器、拦截器这些都是Spring框架中web开发模块所提供的功能,而Spring框架的web开发模块,我们也称为:SpringMVC
SpringMVC不是一个单独的框架,它是Spring框架的一部分,是Spring框架中的web开发模块,是用来简化原始的Servlet程序开发的。
- 外界俗称的SSM,就是由:SpringMVC、Spring Framework、Mybatis三块组成。
- 基于传统的SSM框架进行整合开发项目会比较繁琐,而且效率也比较低,所以在现在的企业项目开发当中,基本上都是直接基于SpringBoot整合SSM进行项目开发的。
Controller层
-
Controller层要先声明两个注解:
@Slf4j :log日志文件
@RestController:自动将方法的返回值转换为JSON格式
它集成了
@Controller
和@ResponseBody
两个注解的功能:- @Controller:表示该类是一个控制器,用于处理 HTTP 请求。
- @ResponseBody:表示该控制器中的方法返回的对象直接作为 HTTP 响应的正文返回,而不是返回一个视图(View)。这通常用于返回 JSON 或 XML 数据。
- @RequestBody:用于接收前端的请求数据。
。
-
路径参数注入注解:用@PathVariable向前端传入路径参数
-
@RequestMapping:抽取公共路径
-
@RequestParam(defaultValue = “1”):设置请求参数默认值
-
Controller层接收前参数的方式:同名形参
-
服务端接收文件:
6、更新功能注解用 :@PutMapping
Mapper层
1、:在动态更新中为了防止最后一项没有更新,倒数第二项会有多余的“,”问题
2、:在动态查询中为了防止最后一项没有查询,倒数第二项会有多余的“and”问题
参数配置化
application.properties
1、@Value 注解:只能一个一个进行外部属性的注入。
常用于外部配置的属性注入,具体用法为:@Value(“&{配置文件中的key}”)
2、@Configuration注解:可以批量注入外部的属性到bean对象的属性中
application.yml
-
基本语法
server: port: 9000 # 定义对象/Map集合 user: name: Tom age: 20 adress: Beijing # 定义数组/List/Set hobby: - java - C - game - sport
JWT令牌
Header(头):记录令牌类型、签名算法。
Payload(有效载荷):携带一些自定义信息、默认信息等。
SIgnature(签名):防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。
过滤器 Filter
@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//因为 tomcat 传入的 request 实际上是 HttpRequest,需要强制转化,这里是多态的思想
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
//1. 获取请求路径
String url = req.getRequestURI().toString();
log.info("请求的url:{}", url);
//2. 判断请求中url是否包含login,如果包含,说明是登录操作,放行
if (url.contains("login")){
log.info("登录操作,放行...");
chain.doFilter(request, response);
return;
}
//3. 获取请求头中的令牌(token)
String jwt = req.getHeader("token");
//4. 判断令牌是否存在,如果不存在,返回错误结果(未登录)
if(!StringUtils.hasLength(jwt)){
log.info("请求头token为空,返回未登录信息");
Result error = Result.error("NOT_LOGIN");
//手动转换 对象json ------------> 阿里巴巴 fastJSON
String notLogin = JSON.toJSONString(error);
res.getWriter().write(notLogin);
return;
}
//5. 解析token,如果解析失败,返回错误结果(未登录)
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) { //jwt 解析失败
e.printStackTrace();
log.info("解析令牌失败,返回未登录的错误信息");
Result error = Result.error("NOT_LOGIN");
//手动转换 对象json ------------> 阿里巴巴 fastJSON
String notLogin = JSON.toJSONString(error);
res.getWriter().write(notLogin);
return;
}
//6. 放行
log.info("令牌合法,放行");
chain.doFilter(request, response);
}
}
拦截器 Interceptor
@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override //目标资源方法运行前放行,返回 true:放行;返回 false,不放行
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
//1. 获取请求路径
String url = req.getRequestURI().toString();
log.info("请求的url:{}", url);
//2. 判断请求中url是否包含login,如果包含,说明是登录操作,放行
if (url.contains("login")){
log.info("登录操作,放行...");
return true;
}
//3. 获取请求头中的令牌(token)
String jwt = req.getHeader("token");
//4. 判断令牌是否存在,如果不存在,返回错误结果(未登录)
if(!StringUtils.hasLength(jwt)){
log.info("请求头token为空,返回未登录信息");
Result error = Result.error("NOT_LOGIN");
//手动转换 对象json ------------> 阿里巴巴 fastJSON
String notLogin = JSON.toJSONString(error);
resp.getWriter().write(notLogin);
return false;
}
//5. 解析token,如果解析失败,返回错误结果(未登录)
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) { //jwt 解析失败
e.printStackTrace();
log.info("解析令牌失败,返回未登录的错误信息");
Result error = Result.error("NOT_LOGIN");
//手动转换 对象json ------------> 阿里巴巴 fastJSON
String notLogin = JSON.toJSONString(error);
resp.getWriter().write(notLogin);
return false;
}
//6. 放行
log.info("令牌合法,放行");
return true;
}
@Override //目标资源方法运行后运行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
@Override //视图渲染完毕后运行,最后运行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}
-
浏览器访问部署在web服务器(Tomcat)的web应用时,过滤器会拦截到请求,执行放行前逻辑,执行放行操作
-
但是Tomcat识别servlet容器,不识别spring容器,所以前端数据传到后端时,要先经过DispatchServlet才能转给spring容器
-
在执行controller的接口方法之前要先执行拦截器中的preHandle的方法,如果返回的结果是true,才能放行
-
controller方法执行完毕后,才能继续执行拦截器中的postHandle和afterCompletion方法
-
拦截器将结果返回给DispatchServlet,最终执行过滤器中的放行后逻辑,给浏览器响应数据
过滤器与拦截器区别
接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口。
拦截范围不同:过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源。
放行的形式不同:过滤器需要调用dofilter()进行放行操作,拦截器只需要return true/false就可以
过滤器和拦截器实现登录校验的逻辑是相同的
全局异常处理器
/**
* 全局异常处理器
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
//@ExceptionHandler(捕获哪一类异常)
@ExceptionHandler(Exception.class) //捕获所有异常
public Result ex(Exception ex){
ex.printStackTrace();
return Result.error("对不起,操作失败,请联系管理员");
}
}