“JSR303和拦截器在Java Web开发中的应用与实践“

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: “JSR303和拦截器在Java Web开发中的应用与实践“

引言

在Java Web开发过程中,我们经常会遇到需要对输入数据进行验证和处理,同时需要对请求进行拦截与控制的需求。为了方便实现这些功能,我们可以使用JSR303验证框架和拦截器技术。本篇博客将介绍JSR303和拦截器的基本概念,并探讨它们在Java Web开发中的应用与实践。

什么是JSR303?

JSR303是一项Java标准规范,也被称为Bean Validation,它提供了一组注解和API用于对JavaBean属性进行验证。通过使用JSR303,我们可以在不编写繁琐的验证逻辑代码的情况下,实现对表单数据的验证和处理。JSR303使得验证过程更加简单和可读,并且是一种广泛应用于Java Web开发中的验证框架。

为什么要使用JSR303?

使用JSR303可以提供以下好处:

  • 简化验证逻辑:通过使用JSR303的注解,我们可以直接在JavaBean属性上添加验证规则,使得验证逻辑更加清晰和简洁。
  • 提高可维护性:将验证规则与业务逻辑分离,使得验证规则可以独立于业务逻辑进行修改和扩展,提高了代码的可维护性。
  • 提供统一验证框架:JSR303是Java标准规范,被广泛应用于Java Web框架中,使用JSR303可以使得不同的Web框架之间的验证方式保持一致,提高了协作的效率。

常用注解

在JSR303中,有许多常用的注解用于实现验证功能,包括:

  • @NotNull:用于标记属性不能为空。
  • @Size:用于指定属性的长度范围。
  • @Pattern:用于指定属性的正则表达式验证规则。
  • @Min:用于指定属性的最小值。
  • @Max:用于指定属性的最大值。
    其他还有很多注解,可以根据具体需求选择合适的注解进行使用。

快速入门JSR303

以下是使用JSR303进行表单验证的快速入门示例:

实体类

package com.yuan.model;
import lombok.ToString;
import javax.validation.constraints.NotBlank;
@ToString
public class Student {
    @NotBlank(message = "编号不能为空")
    private String sid;
    @NotBlank(message = "名字不能为空")
    private String sname;
    @NotBlank(message = "年龄不能为空")
    private String sage;
    @NotBlank(message = "性别不能为空")
    private String ssex;
    public Student(String sid, String sname, String sage, String ssex) {
        this.sid = sid;
        this.sname = sname;
        this.sage = sage;
        this.ssex = ssex;
    }
    public Student() {
        super();
    }
    public String getSid() {
        return sid;
    }
    public void setSid(String sid) {
        this.sid = sid;
    }
    public String getSname() {
        return sname;
    }
    public void setSname(String sname) {
        this.sname = sname;
    }
    public String getSage() {
        return sage;
    }
    public void setSage(String sage) {
        this.sage = sage;
    }
    public String getSsex() {
        return ssex;
    }
    public void setSsex(String ssex) {
        this.ssex = ssex;
    }
}
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29
• 30
• 31
• 32
• 33
• 34
• 35
• 36
• 37
• 38
• 39
• 40
• 41
• 42
• 43
• 44
• 45
• 46
• 47
• 48
• 49
• 50
• 51
• 52
• 53
• 54
• 55
• 56
• 57
• 58
• 59
• 60
• 61

后台校验

//    给数据添加服务端校验
    @RequestMapping("/valiAdd")
    public String valiAdd(@Validated Student student, BindingResult result, HttpServletRequest req){
//        如果服务端验证不通过,有错误
        if(result.hasErrors()){
//            服务端验证了实体类的多个属性,多个属性都没有验证通过
            List<FieldError> fieldErrors = result.getFieldErrors();
            Map<String,Object> map = new HashMap<>();
            for (FieldError fieldError : fieldErrors) {
//                将多个属性的验证失败信息输送到控制台
                System.out.println(fieldError.getField() + ":" + fieldError.getDefaultMessage());
                map.put(fieldError.getField(),fieldError.getDefaultMessage());
            }
            req.setAttribute("errorMap",map);
        }else {
            this.studentBiz.insertSelective(student);
            return "redirect:list";
        }
        return "stu/edit";
    }
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20

JSP页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title></title>
</head>
<body>
<form action="${pageContext.request.contextPath }/${empty s ? 'student/valiAdd' : 'student/edit'}" method="post">
    学生编号:<input type="text" name="sid" value="${s.sid }"><span style="color: red">${errorMap.sid}</span><br>
    学生姓名:<input type="text" name="sname" value="${s.sname }"><span style="color: red">${errorMap.sname}</span><br>
    学生年龄:<input type="text" name="sage" value="${s.sage }"><span style="color: red">${errorMap.sage}</span><br>
    学生性别:<input type="text" name="ssex" value="${s.ssex }"><span style="color: red">${errorMap.ssex}</span><br>
    <input type="submit">
</form>
</body>
</html>
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18

页面效果

通过在JavaBean的属性上添加注解,我们可以指定验证规则。在上述示例中,使用了注解表示该属性不能为空,注解表示该属性的长度范围是2到20之间,注解表示该属性的值必须符合正则表达式"[a-zA-Z0-9]+"。在实际使用中,我们可以通过调用验证器来验证数据是否符合规则。@NotNull@Size@Pattern

拦截器

什么是拦截器

拦截器是Java Web开发中常见的一种技术,它允许在请求到达目标资源之前或之后对请求进行处理。拦截器可以拦截请求和响应,并在处理过程中对它们进行修改和控制。拦截器在开发过程中具有广泛的应用,用于实现身份验证、日志记录、性能监控等功能。

拦截器与过滤器

虽然拦截器和过滤器在功能上有一些相似之处,但它们在实现方式和应用场景上有所不同。

  • 过滤器是基于Servlet规范的,它通过在web.xml文件中配置,并作用于整个应用或者特定的URL模式。过滤器可以在请求到达目标资源之前或之后进行处理,但其处理方式是基于Servlet API的。过滤器通常用于请求和响应的预处理和后处理。
  • 拦截器是基于Java反射机制的,它通常与特定的框架或技术相关联,比如Spring框架。拦截器可以更加细粒度地进行控制,可以通过在配置文件或注解中添加拦截器的方式来指定拦截的目标资源。

应用场景

拦截器在Java Web开发中具有广泛的应用场景,包括但不限于以下几个方面:

  • 身份验证和权限控制:拦截器可以用于验证用户的身份,并对用户的访问权限进行控制,以确保只有具备相应权限的用户可以访问受限资源。
  • 日志记录:拦截器可以用于记录请求和响应的日志信息,包括请求参数、处理时间、返回结果等,便于后期的问题排查和系统分析。
  • 参数处理和转换:拦截器可以在请求到达目标资源之前对请求参数进行处理和转换,使得目标资源能够更加方便地获取到需要的数据。
  • 性能监控:拦截器可以用于统计和监控系统的性能指标,例如请求处理时间、访问频率等,以便及时发现潜在的性能问题。

快速入门拦截器

以下是使用拦截器进行身份验证和权限控制的快速入门示例:

  • 1.拦截器链
package com.yuan.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class OneInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("【OneInterceptor】:preHandle...");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("【OneInterceptor】:postHandle...");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("【OneInterceptor】:afterCompletion...");
    }
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
package com.yuan.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TwoInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("【TwoInterceptor】:preHandle...");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("【TwoInterceptor】:postHandle...");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("【TwoInterceptor】:afterCompletion...");
    }
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
<mvc:interceptors>
        <!--2) 多拦截器(拦截器链)-->
        <mvc:interceptor>
        <!--这个是拦截所有的-->
            <mvc:mapping path="/**"/>
            <bean class="com.yuan.interceptor.OneInterceptor"/>
        </mvc:interceptor>
        <mvc:interceptor>
         <!--这个是只拦截/studnt路径下所有的-->
            <mvc:mapping path="/student/**"/>
            <bean class="com.yuan.interceptor.TwoInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
  • 2.登录

登录拦截器

package com.yuan.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("【implements】:preHandle...");
        StringBuffer url = request.getRequestURL();
        if (url.indexOf("/login") > 0 || url.indexOf("/logout") > 0){
            //        如果是 登录、退出 中的一种
            return true;
        }
//            代表不是登录,也不是退出
//            除了登录、退出,其他操作都需要判断是否 session 登录成功过
        String uname = (String) request.getSession().getAttribute("uname");
        if (uname == null || "".equals(uname)){
            response.sendRedirect("/page/login");
            return false;
        }
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29
• 30
• 31
• 32
• 33
• 34
• 35
• 36
• 37

Login Web层

package com.yuan.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@Controller
public class LoginController {
    @RequestMapping("/login")
    public String login(HttpServletRequest req){
        String uname = req.getParameter("uname");
        HttpSession session = req.getSession();
        if ("yh".equals(uname)){
            session.setAttribute("uname",uname);
        }
        return "redirect:/student/list";
    }
    @RequestMapping("/logout")
    public String logout(HttpServletRequest req){
        req.getSession().invalidate();
        return "redirect:/student/list";
    }
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26

login.jsp

<%--
  Created by IntelliJ IDEA.
  User: yuanh
  Date: 2023/9/11
  Time: 18:38
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="/login?uname=yh">登录</a>
</body>
</html>
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17

配置拦截器

<mvc:interceptors>
        <bean class="com.yuan.interceptor.LoginInterceptor"></bean>
    </mvc:interceptors>
• 1
• 2
• 3
• 4

以我的代码为例,如果登录点击进去携带的参数不为空并且为yh就可以进入主界面,如果不是就会被拦截一直在登录界面

总结

本篇博客介绍了JSR303在这里插入代码片验证框架和拦截器技术在Java Web开发中的应用与实践。通过使用JSR303,我们可以简化表单验证逻辑,并提高代码的可维护性。拦截器则可以用于实现身份验证、日志记录、性能监控等功能,提升系统的安全性和可观测性。通过深入掌握和灵活应用JSR303和拦截器,我们可以更好地开发出高质量的Java Web应用。

希望本篇博客能够帮助你对JSR303和拦截器有更深入的理解,并能在实际项目中应用它们来提升开发效率和代码质量。


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
3天前
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。
|
3天前
|
数据采集 Java 数据挖掘
Java IO异常处理:在Web爬虫开发中的实践
Java IO异常处理:在Web爬虫开发中的实践
|
3天前
|
Java UED 开发者
Java中的异常处理:理解与实践
【9月更文挑战第3天】在Java编程中,异常处理是保持程序健壮性的关键。本文将引导你了解Java的异常机制,从基本的try-catch结构到自定义异常类的创建,以及如何优雅地处理异常情况。我们将一起探讨异常处理的最佳实践,并学习如何在代码中实现它们,以确保你的应用程序能够优雅地处理运行时错误。
10 2
|
5天前
|
数据采集 存储 前端开发
Java爬虫开发:Jsoup库在图片URL提取中的实战应用
Java爬虫开发:Jsoup库在图片URL提取中的实战应用
|
7天前
|
Java 调度
Java中的多线程基础与实践
【8月更文挑战第31天】本文将深入浅出地讲解Java中多线程的基础知识,并通过实例展示如何在Java程序中实现多线程。我们将从多线程的基本概念出发,逐步深入到线程的创建、控制以及同步机制,最后通过一个简易版的生产者消费者模型来实践这些知识点。文章旨在帮助初学者快速掌握多线程编程的关键技能,并理解其背后的原理。
|
1天前
|
关系型数据库 Java MySQL
"解锁Java Web传奇之旅:从JDK1.8到Tomcat,再到MariaDB,一场跨越数据库的冒险安装盛宴,挑战你的技术极限!"
【9月更文挑战第6天】在Linux环境下安装JDK 1.8、Tomcat和MariaDB是搭建Java Web应用的关键步骤。本文详细介绍了使用apt-get安装OpenJDK 1.8、下载并配置Tomcat,以及安装和安全设置MariaDB(MySQL的开源分支)的方法。通过这些步骤,您可以快速构建一个稳定、高效的开发和部署环境,并验证各组件是否正确安装和运行。这为您的Java Web应用提供了一个坚实的基础。
9 0
|
7天前
|
C# Windows 开发者
当WPF遇见OpenGL:一场关于如何在Windows Presentation Foundation中融入高性能跨平台图形处理技术的精彩碰撞——详解集成步骤与实战代码示例
【8月更文挑战第31天】本文详细介绍了如何在Windows Presentation Foundation (WPF) 中集成OpenGL,以实现高性能的跨平台图形处理。通过具体示例代码,展示了使用SharpGL库在WPF应用中创建并渲染OpenGL图形的过程,包括开发环境搭建、OpenGL渲染窗口创建及控件集成等关键步骤,帮助开发者更好地理解和应用OpenGL技术。
34 0
|
7天前
|
前端开发 Java UED
JSF遇上Material Design:一场视觉革命,如何让传统Java Web应用焕发新生?
【8月更文挑战第31天】在当前的Web开发领域,用户体验和界面美观性至关重要。Google推出的Material Design凭借其独特的动画、鲜艳的颜色和简洁的布局广受好评。将其应用于JavaServer Faces(JSF)项目,能显著提升应用的现代感和用户交互体验。本文介绍如何通过PrimeFaces等组件库在JSF应用中实现Material Design风格,包括添加依赖、使用组件及响应式布局等步骤,为用户提供美观且功能丰富的界面。
14 0
|
7天前
|
Java 前端开发 Apache
Apache Wicket与Spring MVC等Java Web框架大PK,究竟谁才是你的最佳拍档?点击揭秘!
【8月更文挑战第31天】在Java Web开发领域,众多框架各具特色。Apache Wicket以组件化开发和易用性脱颖而出,提高了代码的可维护性和可读性。相比之下,Spring MVC拥有强大的生态系统,但学习曲线较陡;JSF与Java EE紧密集成,但在性能和灵活性上略逊一筹;Struts2虽成熟,但在RESTful API支持上不足。选择框架时还需考虑社区支持和文档完善程度。希望本文能帮助开发者找到最适合自己的框架。
17 0
|
7天前
|
Java Spring 开发者
Java Web开发新潮流:Vaadin与Spring Boot强强联手,打造高效便捷的应用体验!
【8月更文挑战第31天】《Vaadin与Spring Boot集成:最佳实践指南》介绍了如何结合Vaadin和Spring Boot的优势进行高效Java Web开发。文章首先概述了集成的基本步骤,包括引入依赖和配置自动功能,然后通过示例展示了如何创建和使用Vaadin组件。相较于传统框架,这种集成方式简化了配置、提升了开发效率并便于部署。尽管可能存在性能和学习曲线方面的挑战,但合理的框架组合能显著提升应用开发的质量和速度。
15 0
下一篇
DDNS