Dao
- 操作数据库的接口定义:StudentDao
/** * ClassName: StudentDao * Package: cw.springmvc.study.dao * Description: * * @Author tcw * @Create 2023-05-28 15:57 * @Version 1.0 */ public interface StudentDao { /** * 插入学生信息 * * @param student 学生信息 * @return 影响数据库的条数 */ int insertStudent(Student student); /** * 查询全部学生信息 * * @return 学生信息 */ List<Student> selectStudents(); }
- SQL映射配置文件:StudentDao
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cw.springmvc.study.dao.StudentDao"> <insert id="insertStudent"> insert into t_student(name, age) values (#{name}, #{age}); </insert> <select id="selectStudents" resultType="Student"> select id, name, age from t_student order by id desc; </select> </mapper>
Service
- 业务层接口:StudentService
package cw.springmvc.study.service; import cw.springmvc.study.pojo.Student; import java.util.List; /** * ClassName: StudentService * Package: cw.springmvc.study.service * Description: * * @Author tcw * @Create 2023-05-28 16:05 * @Version 1.0 */ public interface StudentService { /** * 添加学生信息 * * @param student 学生信息 * @return */ int addStudent(Student student); /** * 查询所有学生信息 * * @return 学生信息 */ List<Student> findStudents(); }
- 业务层接口实现类:StudentServiceImpl
package cw.springmvc.study.service.impl; import cw.springmvc.study.dao.StudentDao; import cw.springmvc.study.pojo.Student; import cw.springmvc.study.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * ClassName: StudentServiceImpl * Package: cw.springmvc.study.service.impl * Description: * * @Author tcw * @Create 2023-05-28 16:07 * @Version 1.0 */ @Service public class StudentServiceImpl implements StudentService { @Autowired // 根据类型自动装配 private StudentDao studentDao; @Override public int addStudent(Student student) { return studentDao.insertStudent(student); } @Override public List<Student> findStudents() { return studentDao.selectStudents(); } }
controller
package cw.springmvc.study.controller; import cw.springmvc.study.pojo.Student; import cw.springmvc.study.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import java.util.List; /** * ClassName: StudentController * Package: cw.springmvc.study.controller * Description: * * @Author tcw * @Create 2023-06-05 18:33 * @Version 1.0 */ @Controller @RequestMapping("/student") public class StudentController { @Autowired // 自动装配 private StudentService studentService; /** * 处理新增学生信息请求 * * @return 视图和数据 */ @RequestMapping("/add") public ModelAndView addStudent(Student student) { // 调用Service处理新增学生信息业务 int cnt = studentService.addStudent(student); ModelAndView mv = new ModelAndView(); // 添加响应数据 if (cnt > 0) { mv.addObject("msg", "学生【" + student.getName() + "】注册成功"); } else { mv.addObject("msg", "学生【" + student.getName() + "】注册失败"); } // 设置响应视图 mv.setViewName("result"); return mv; } /** * 查询所有的学生信息 * * @return 所有的学生信息 */ @RequestMapping("/list") @ResponseBody public List<Student> selectStudentAll() { // 查询学生信息 return studentService.findStudents(); } }
JSP
- index.jsp
<%-- Created by IntelliJ IDEA. User: cw Date: 2023-06-05 Time: 18:43 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.js"></script> <script> $(function () { $("button").click(function (){ // 发请求 $.ajax({ url: "./student/list", type:"get", dataType:"json", success(data) { let newData = data.map((d) => { return d.id + " " + d.name + " " + d.age + "<br/>"; }) $("div").html(""); // 清除 $("div").append(newData); // 追加新数据 } }) }) }) </script> </head> <body> <p>SSM</p> <form action="./student/add" method="post"> 姓名:<input name="name" type="text"><br/> 年龄:<input name="age" type="text"><br/> <input value="提交" type="submit"> </form> <br/> <button>查询学生信息</button> <div></div> </body> </html>
- result.jsp
<%-- Created by IntelliJ IDEA. User: cw Date: 2023-06-05 Time: 18:41 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> <h2>${msg}</h2> </body> </html>
测试
请求转发与重定向
- SpringMVC 框架把原来 Servlet 中的请求转发和重定向操作进行了封装。可以使用简单的方式实现转发和重定向。
- 使用 forward 表示转发,实现 request.getRequestDispatcher(“xx.jsp”).forward()
- 使用 redirect 表示重定向,实现 response.sendRedirect(“xxx.jsp”)
- forward 和 redirect 都是 SpringMVC 框架中的关键字,两个关键字都不和视图解析器一同工作
请求转发
- 通过处理器方法返回ModelAndView,实现请求转发
- 语法:
mv.setViewName("forward:视图文件完整路径")
- 注意:forward 不和视图解析器一同使用,不管有没有配置视图解析器,使用forward进行请求转发都相当于没有视图解析器。
- 使用 forward 关键字进行请求转发为显示转发,该种方式主要用于当想要进行请求转发但是要转发到的页面没有在视图解析器配置的路径中的情况下,使得请求转发可以不受视图解析器的限制,实现可以转发到视图解析器以外的页面
- 视图解析器配置如下:
<!-- 视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/"/> <property name="suffix" value=".jsp"/> </bean>
- 控制器:
@Controller public class MyController { @RequestMapping(value = "/some.do") public ModelAndView doSome(String name, String age) { ModelAndView mv = new ModelAndView(); System.out.println(123); mv.addObject("name", name); mv.addObject("age", age); // 进行请求转发 mv.setViewName("forward:./WEB-INF/view/show.jsp"); return mv; } }
- show.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <p>姓名:${name}</p> <p>年龄:${age}</p> </body> </html>
请求重定向
- 通过处理器方法返回ModelAndView,实现请求重定向
- 语法:
mv.setViewName("redirect:视图文件完整路径")
- 注意:redirect 不和视图解析器一同使用,不管有没有配置视图解析器,使用redirect进行请求重定向都相当于没有视图解析器。
- 控制器:
@Controller public class MyController { @RequestMapping(value = "/some.do") public ModelAndView doSome(String name, String age) { ModelAndView mv = new ModelAndView(); mv.addObject("name111", name); mv.addObject("age111", age); System.out.println("name: " + name + " age: " + age); // 进行请求重定向 // http://localhost:8080/springmvc/show222.jsp?name111=%E5%BC%A0%E4%B8%89&age111=23 mv.setViewName("redirect:./show222.jsp"); return mv; } }
- 在进行请求重定向的时候,添加到ModelAndView中的数据,框架会将Model中的简单类型的数据转为String使用,作为向请求重定向地址的请求参数使用,使得在两次请求之间可以传递数据
- 注意:请求重定向是一次全新的从浏览器发出的请求,WEB-INF下的资源是不能被浏览器请求访问的
- jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <!-- 请求重定向,是全新的一次请求,参数在request对象上, 不在本次的请求作用域中 --> <!-- param 请求参数集合 --> <p>姓名:${param.name111}</p> <p>年龄:<%= request.getParameter("age111") %></p> </body> </html>
异常处理
- 之前对代码可能出现异常的处理方法:
public void fun() { try { } catch (Exception e){ } }
- SpringMVC 框架中将处理异常的代码(非业务逻辑代码)抽取出来,在一个统一的位置定义异常的处理,采用面向切面编程的方式,来处理异常
- springmvc框架采用的是统一,全局的异常处理。把controller中的所有异常处理都集中到一个地方,采用的是aop的思想,把业务逻辑和异常处理代码分开,解耦合。
- springmvc框架提供了两个注解进行异常的处理:@ExceptionHandler、@ControllerAdvice
自定义异常类
package cw.springmvc.exception; /** * ClassName: MyUserException * Package: cw.springmvc.exception * Description: * * @Author tcw * @Create 2023-06-05 22:31 * @Version 1.0 */ public class MyUserException extends Exception{ public MyUserException() { super(); } public MyUserException(String message) { super(message); } }
package cw.springmvc.exception; /** * ClassName: AgeException * Package: cw.springmvc.exception * Description: * * @Author tcw * @Create 2023-06-05 22:32 * @Version 1.0 */ public class AgeException extends MyUserException{ public AgeException() { super(); } public AgeException(String message) { super(message); } }
package cw.springmvc.exception; /** * ClassName: NameException * Package: cw.springmvc.exception * Description: * * @Author tcw * @Create 2023-06-05 22:32 * @Version 1.0 */ public class NameException extends MyUserException{ public NameException() { super(); } public NameException(String message) { super(message); } }
处理器类
package cw.springmvc.controller; import cw.springmvc.exception.AgeException; import cw.springmvc.exception.MyUserException; import cw.springmvc.exception.NameException; import cw.springmvc.pojo.User; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import javax.sound.midi.Soundbank; import java.util.ArrayList; import java.util.List; /** * ClassName: MyController * Package: cw.springmvc.controller * Description: * * @Author tcw * @Create 2023-05-21 20:24 * @Version 1.0 */ @Controller public class MyController { @RequestMapping(value = "/some.do") public ModelAndView doSome(String name, Integer age) throws MyUserException { ModelAndView mv = new ModelAndView(); // 根据请求参数抛出异常,将异常交给SpringMVC框架处理 if (!"admin".equals(name)) { throw new NameException("用户名不正确."); } if (age == null || age < 0) { throw new AgeException("年龄不正确."); } mv.addObject("name", name); mv.addObject("age", age); mv.setViewName("show"); return mv; } }
异常处理器
- 当控制器发生异常时,会停止控制器方法的执行,跳转到异常处理器类中,进行处理异常方法的匹配
- 异常处理类,也是组件,所以需要配置包扫描,进行异常处理类组件扫描
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface ControllerAdvice { @AliasFor("basePackages") String[] value() default {}; @AliasFor("value") String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; Class<?>[] assignableTypes() default {}; Class<? extends Annotation>[] annotations() default {}; }
- @ControllerAdvice:标注该类是异常处理类
- @ExceptionHandler:标注异常处理方法处理的异常类型,如果没有指定处理的异常类型,那么该方法就是用于处理没有异常处理方法匹配的异常,没有指定处理的异常类型的方法只能有一个
- 要使用这两个注解,需要在SpringMVC配置文件中配置注解驱动
package cw.springmvc.handler; import cw.springmvc.exception.AgeException; import cw.springmvc.exception.NameException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.servlet.ModelAndView; /** * ClassName: GlobalExceptionHandler * Package: cw.springmvc.handler * Description: * 全局异常处理器 * ControllerAdvice注解:控制器通知、控制器增强 * 给控制器增加功能,增加异常处理功能 * ControllerAdvice注解使用在类上 * 对于控制器通知组件需要配置组件扫描器 * * @Author tcw * @Create 2023-06-05 22:39 * @Version 1.0 */ // 标注为控制器异常处理组件 @ControllerAdvice public class GlobalExceptionHandler { /** * 定义方法,处理发生的异常 * 处理异常的方法和控制器方法的定义方式一样, * 控制器方法可以怎么定义,处理异常的方法就可以怎么定义 * * 处理NameException的异常 * * @param e 表示Controller中抛出的异常对象 * 通过这个形参可以获取发生的异常信息 * @return */ // @ExceptionHandler(异常的class):表示该方法处理异常的类型 @ExceptionHandler(value = {NameException.class}) public ModelAndView doNameException(Exception e) { // 异常的处理逻辑: // 1.需要把异常记录下来,记录到数据库或日志文件 // 记录日志发生的时间、哪个方法发生、异常错误的内容 // 2.发送通知,把异常的信息通过邮件、短信、微信发送给相关人员 // 3.给用户友好的提示 ModelAndView mv = new ModelAndView(); mv.addObject("msg", "用户名必须是admin"); mv.addObject("exception", e); mv.setViewName("nameError"); return mv; } /** * 处理年龄异常 AgeException * * @param e 异常对象 * @return */ @ExceptionHandler(value = {AgeException.class}) public ModelAndView doAgeException(Exception e) { ModelAndView mv = new ModelAndView(); mv.addObject("msg", "年龄不能为空,且应该大于0"); mv.addObject("exception", e); mv.setViewName("ageError"); return mv; } /** * 处理其他异常,处理没有相匹配的异常处理方法的异常 * 会先与有指定处理具体异常的方法进行匹配,都不能处理发生的异常 * 即没有方法匹配 * 就使用该方法进行处理,使用没有指定具体处理异常类型的方法处理 * 只能有一个默认处理异常的 * * @param e 异常对象 * @return */ @ExceptionHandler public ModelAndView doOtherException(Exception e) { ModelAndView mv = new ModelAndView(); mv.addObject("msg", "未知异常"); mv.addObject("exception", e); mv.setViewName("defaultError"); return mv; } }
JSP
- show.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <p>姓名:${name}</p> <p>年龄:${age}</p> </body> </html>
- ageError.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>年龄异常</h1> <p>${msg}</p> <p>${exception.message}</p> </body> </html>
- nameError.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>姓名异常</h1> <p>${msg}</p> <p>${exception.message}</p> </body> </html>
- defaultError.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>未知异常</h1> <p>${msg}</p> <p>${exception.message}</p> </body> </html>
- index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="./some.do" method="post"> name:<input type="text" name="name"><br/> age:<input type="text" name="age"><br/> <input type="submit" name="submit"><br/> </form> </body> </html>