SpringMVC

开发步骤

1.导入SpringMVC包

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.3.25</version>
</dependency>

<dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>compile</scope>
   </dependency>

2.配置SpringMVC核心控制器DispathcerServlet和监听器

<!--配置spring监听器-->
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

在web.xml中添加

<servlet>
  <servlet-name>DispatcherServlet</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
     <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>DispatcherServlet</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

3.编写Controller类和视图

在com.包名下创建controller包,然后创建Controller类

4.将Controller使用注解配置到Spring容器中(@Controller)

@Controller
public class UserController {
    @RequestMapping("/quick")
    public String Save(){
        System.out.println("Controller save running...");
        return  "success.jsp";
    }
}

5.配置spring-mvc.xml文件(配置组件扫描)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
    <context:component-scan base-package="com.zy.controller"/>
</beans>

6.执行访问测试

SpringMVC执行流程

image-20230311143900517

  1. 用户发送请求到前端控制器DispatcherServlet
  2. DipatcherServlet收到请求调用HandlerMapping处理器映射器
  3. 处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器,一并返回给DispatcherServlet
  4. DispatcherServlet调用HandlerAdaoter处理器适配器
  5. HandlerAdapter经过适配调用具体的处理器(Controller)
  6. Controller执行完成后返回ModelAndView
  7. HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet
  8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器
  9. ViewReslover解析后返回具体View
  10. DispatcherServlet根据View进行渲染视图,DispatcherServlet响应用户

SpringMVC注解解析

@RequestMapping

作用:用于建议请求URL和处理请求方法之间的对应关系

位置:

  • 类上,请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录。
  • 方法上,请求URL的第二级访问目录,与类上是使用标注的一级目录组成访问虚拟路径
  • value:用户指定请求的URL。它和Path属性的作用是一样的
  • method:用户指定请求的方法@RequestMapping(value = "/quick",method = RequestMethod.POST)
  • params:用户指定限制请求参数的条件。它支持简单的表达式,要求参数的key和value必须配置一样。
  • params=["accountName"],表示请求参数必须有accountName
  • params=["moeny!100"],表示请求参数中money不能是100

SpringMVC组件扫描

spring-mvc.xml用于扫描Controller层

<context:component-scan base-package="com.zy.controller"/>

<context:component-scan base-package="com.zy">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

SpringMVC的视图XML配置解析(资源解析器)

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/jsp/"></property>
    <property name="suffix" value=".jsp"></property>
</bean>

配置完成后可以直接返回return "success";,不需要retrun "/jsp/success.jsp"

SpringMVC知识要点

SpringMVC的相关组件

  • 前端控制器:DispatcherServlet
  • 处理器映射器:HandlerMapping
  • 处理器适配器:HandlerAdapter
  • 处理器:Handler
  • 视图解析器:ViewResolver
  • 视图:view

SpringMVC的注解和配置

  • 请求映射注解:@RequestMapping
  • 视图解析配置<property name="prefix" value="/jsp/"></property> <property name="suffix" value=".jsp"></property>

SpringMVC的数据响应

数据响应方式

1)页面跳转

  • 直接返回字符串
  • 通过ModelAndView对象返回

2)回写数据

  • 直接返回字符串
  • 返回对象或集合

页面跳转

1.返回字符串形式

直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转。

2.返回ModelAndView对象

<%@ page language="java" pageEncoding="utf-8" isELIgnored="false"%>
<h1>Success: ${username}</h1>
@RequestMapping(value = "/quick2",method = RequestMethod.GET)
public ModelAndView Save2(){
    /*
    * Model 模型 封装数据
    * View 视图 展示数据
    * */
    ModelAndView modelAndView = new ModelAndView();
    //设置模型数据
    modelAndView.addObject("username","itcast");
    //设置视图名称
    modelAndView.setViewName("success");
    return modelAndView;
}

或者

@RequestMapping(value = "/quick3",method = RequestMethod.GET)
public ModelAndView Save3(ModelAndView modelAndView){
    //设置模型数据
    modelAndView.addObject("username","itcast");
    //设置视图名称
    modelAndView.setViewName("success");
    return modelAndView;
}

@RequestMapping(value = "/quick4", method = RequestMethod.GET)
public String Save4(Model model) {
    model.addAttribute("username","zy");
    return "success";
}

回写数据

直接返回字符串

① 通过SpringMVC框架注入的response对象,使用response.getWriter().print("hello")回写数据,此时不需要视图跳转,业务方法返回值为void。

@RequestMapping(value = "/quick6", method = RequestMethod.GET)
public void Save6(HttpServletResponse response) throws IOException {
    response.getWriter().println("hello zy");
}

② 将需要回写的字符串直接返回,但此时需要通过@ResponseBody注解告知SpringMVC框架,方法返回的字符串不是跳转是直接http响应体中返回

@RequestMapping(value = "/quick7", method = RequestMethod.GET)
@ResponseBody
public String Save7() throws IOException {
    return "zy";
}

返回json格式数据

导入json包

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.13.5</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.13.5</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.13.5</version>
</dependency>

实现

@RequestMapping(value = "/quick8", method = RequestMethod.GET)
@ResponseBody
public String Save8() throws IOException {
    User user = new User();
    user.setUsername("zy");
    user.setAge(30);
    ObjectMapper objectMapper = new ObjectMapper();
    String Json = objectMapper.writeValueAsString(user);
    return Json;
}

返回对象和集合

在spring-mvc.xml中配置处理器映射器

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
        </list>
    </property>
</bean>

然后就能直接返回对象,返回的数据为json格式

@RequestMapping(value = "/quick9", method = RequestMethod.GET)
@ResponseBody
public User Save9() throws IOException {
    User user = new User();
    user.setUsername("zy");
    user.setAge(30);
    return user;
}

或者在spring-mvc.xml使用mvc注解驱动

xmlns:mvc="http://www.springframework.org/schema/mvc"
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
<mvc:annotation-driven/>

SpringMVC获取请求数据

1.获得请求参数

客户端请求参数的格式是:name=value&name=value。。。

SpringMVC可以接收如下类型的参数:

  • 基本类型参数
  • POJO类型参数
  • 数组类型参数
  • 集合类型参数

2.获得基本类型参数

Controller中的业务方法的参数名称要与请求参数的name一直,参数值会自动映射匹配

http://localhost:8080/zy_spring_mvc_war_exploded/quick10?username=zy&age=18

@RequestMapping(value = "/quick10", method = RequestMethod.GET)
@ResponseBody
public void Save10(String username,int age) throws IOException {
    System.out.println(username);
    System.out.println(age);
}

3.获取POJO类型参数

Controller中的业务方法的POJO参数的属性名要与请求参数的name一致,参数值会自动映射匹配

http://localhost:8080/zy_spring_mvc_war_exploded/quick11?username=zy&age=18

@RequestMapping(value = "/quick11", method = RequestMethod.GET)
@ResponseBody
public void Save11(User user) throws IOException {
    System.out.println(user);
}

4.获取数组类型参数

http://localhost:8080/zy_spring_mvc_war_exploded/quick12?strs=aaa&strs=bbb

@RequestMapping(value = "/quick12", method = RequestMethod.GET)
@ResponseBody
public void Save12(String[] strs) throws IOException {
    System.out.println(Arrays.asList(strs));
}

5.获得集合类型参数

[
    {
        "username":"zy",
        "age":18
    },
    {
        "username":"zz",
        "age":18
    }
]
@RequestMapping(value = "/quick13", method = RequestMethod.POST)
@ResponseBody
public void Save13(@RequestBody List<User> userList) throws IOException {
    System.out.println(userList);
}

6.请求数据乱码问题

在idea中添加

-Dfile.encoding=UTF-8

image-20230312132617849

在web.xml中配置

<filter>
  <filter-name>CharacterEncodingFilter</filter-name>
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  <init-param>
    <param-name>encoding</param-name>
    <param-value>UTF-8</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>CharacterEncodingFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

7.参数绑定注解@RequestParam

当请求的参数名称与Contoller的业务方法参数名称不一致时,就需要通过@RequestParam注解显示绑定

http://localhost:8080/zy_spring_mvc_war_exploded/quick14?name=张杨

@RequestMapping(value = "/quick14", method = RequestMethod.GET)
@ResponseBody
public void Save14(@RequestParam("name") String username) throws IOException {
    System.out.println(username);
}

注解@RequestParam参数

value:与请求参数名称一样

required:指定请求参数是否必须,默认为true

defalutValue:当没有指定请求参数时,则使用指定的默认值赋值

8.获得Restful风格参数(@PathVariable)

http://localhost:8080/zy_spring_mvc_war_exploded/quick15/张杨

@RequestMapping(value = "/quick15/{username}", method = RequestMethod.GET)
@ResponseBody
public void Save15(@PathVariable("username") String username) throws IOException {
    System.out.println(username);
}

9.自定义类型转换器

  • SpringMVC默认已经提供了一些常用的类型转换器,例如客户端提交的字符转换成int类型进行参数设置。
  • 但是不是所有的数据类型都提供了转换器,没有提供的就需要自定义转换器,例如:日期类型的数据就需要自己定义转换器。

自定义类型转换器的开发步骤

①定义转换器类实现Converter接口

创建com.converter包和DataConverter类,基础Converter<String, Date>接口

public class DataConverter implements Converter<String, Date> {
    @Override
    public Date convert(String dateStr) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = format.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}

②在spring-mvc配置文件中声明转换器

<bean id="ConversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="com.zy.converter.DataConverter"></bean>
        </list>
    </property>
</bean>

③在中引用转换器

<mvc:annotation-driven conversion-service="ConversionService"/>

10.获得Servlet相关API

SpringMVC支持使用原始ServletApi对象作为控制器方法参数进行注入,常用对象如下:

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
@RequestMapping(value = "/quick17", method = RequestMethod.GET)
@ResponseBody
public void Save17(HttpServletRequest request, HttpServletResponse response, HttpSession httpSession) throws IOException {
    System.out.println(request);
    System.out.println(response);
    System.out.println(httpSession);
}

11.获取请求头

1.@RequestHeader

使用@RequestHeader可以获得请求头信息,相当于web阶段学习的request.getHeader(name)

@RequestHeader注解属性如下

  • value:请求头的名称
  • required:是否必须携带请求头
@RequestMapping(value = "/quick18", method = RequestMethod.GET)
@ResponseBody
public void Save18(@RequestHeader(value = "User-Agent",required = false) String user_Agent) throws IOException {
    System.out.println(user_Agent);
}

2.@CookieValue

使用@CookieValue可以获得指定Cookie的值

@CookieValue注解的属性如下:

  • value:指定cookie的名称
  • required:是否必须携带此cookie
@RequestMapping(value = "/quick19", method = RequestMethod.GET)
@ResponseBody
public void Save19(@CookieValue(value = "JSESSIONID",required = false) String jessionId) throws IOException {
    System.out.println(jessionId);
}

12.单文件上传步骤

①导入fileupload和io坐标(pom.xml)

<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.5</version>
</dependency>
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.6</version>
</dependency>

②在spring-mvc.xml中配置文件上传解析器

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="UTF-8"/>
    <property name="maxUploadSize" value="50000"/>
</bean>

③编写文件上传代码

<form action="/quick20" method="post" enctype="multipart/form-data">
    名称:<input type="text" name="username"/><br/>
    文件:<input type="file" name="upload"/><br/>
    <input type="submit" value="提交"/>
</form>
@RequestMapping(value = "/quick20", method = RequestMethod.POST)
@ResponseBody
public void Save20(String username, MultipartFile upload) throws IOException {
    System.out.println(username);
    String originalFilename = upload.getOriginalFilename();
    upload.transferTo(new File("D:\\Spring入门开发\\"+originalFilename));
}

13.多文件上传实现

SpringMVC静态资源访问的开启

在sping-mvc.xml中添加

<mvc:resources mapping="/路径/**" location="/路径/"/> 或者

<mvc:defalut-servlet-handler/>

SpringMVC拦截器

1.1拦截器(interceptor)的作用

SpringMVC的拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。

将拦截器按一定的顺序联结成一条链,这条链成为拦截器链(Interceptor Chain),在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用,拦截器也是AOP思想的具体实现。

1.2拦截器和过滤器的区别

区别 过滤器(Filter) 拦截器(Interceptor)
使用范围 是servlet规范中的一部分,任何Java Web工程都可以使用 是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用
拦截范围 在url-pattern中配置了/*之后,可以对所有要访问的资源拦截 在<mvc:mapping path=/>中配置了/**之后,也可以对所有资源进行拦截,但是可以通过<mvc:exclude-mapping path=/>标签排除不需要拦截的资源

1.3 拦截器快速入门

三步:

① 创建拦截器类实现HandlerInterceptor接口

在com.名字.interceptor包中创建Myinterceptor类

public class Myinterceptorone implements HandlerInterceptor {
    //在目标方法执行之前执行
    public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        //如果为false ,后面的方法都不会执行
        return true/false;
    }
    //在目标方法执行之后 视图返回之前执行
    public void postHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }
    //在流程都执行完毕后 执行
    public void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
}



public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        String param = request.getParameter("param");
        if("yes".equals(param)){
            return true;
        }else {
            request.getRequestDispatcher("/error.jsp").forward(request,response);
            return false;
        }
    }

//在目标方法执行之后 视图返回之前执行
    public void postHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        modelAndView.addObject("name","zzzzzzz");
        System.out.println("postHandle");
    }

② 在spring-mvc.xml配置拦截器

<mvc:interceptors>
    <mvc:interceptor>
        <!--对哪些资源执行拦截操作-->
        <mvc:mapping path="/**"/>
        <bean class="com.zy.interceptor.Myinterceptorone"/>
    </mvc:interceptor>
</mvc:interceptors>

③ 测试拦截器的拦截效果

@Controller
public class TargetController {
    @RequestMapping("/target")
    public ModelAndView show(){
        System.out.println("目标资源执行。。。");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("name","zy");
        modelAndView.setViewName("index");
        return modelAndView;
    }
}

image-20230312215629242

1.4拦截器方法说明

方法名 说明
preHandler() 方法将在请求处理之前进行调用,该方法的返回值是布尔值Boolean类型的,当它返回为false时,表示请求结束,后续的Interceptor和Controller都不会在执行;当返回值为true时就会继续调用下一个Interceptor的preHandler方法。
postHandle() 该方法是在当前请求进行处理之后被调用,前提是preHandler方法的返回值为true是才能被调用,且它会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView对象进行操作。
afterCompletion() 该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行,前提是preHandler方法的返回值为true时才能被调用

1.5案例-用户登录权限控制

需求:用户没有登录的情况下,不能对后台菜单进行访问操作,点击菜单跳转到登录页面,只有用户登录成功后才能进行后台功能操作。

SpringMVC异常处理

1.1异常处理思路

系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发送。

系统的Dao、Service、Controller出现都通过throws Exception向上抛出,最后有SpringMVC前端控制器交由异常处理器进行异常处理

1.2异常处理的两种方式

  • 使用SpringMVC提供的简单异常处理器SimpleMappingExceptionResolver
  • 实现Spring的异常处理接口HanlderExptionResolver自定义自己的异常处理器

简单异常处理器SimpleMappingExceptionResolver

<!--2、配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

<!--配置异常处理器-->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!--        <property name="defaultErrorView" value="error"/>-->
        <property name="exceptionMappings">
            <map>
                <entry key="java.lang.ClassCastException" value="error1"></entry>
                <entry key="com.itheima.exception.MyException" value="error2"></entry>
            </map>
        </property>
    </bean>

自定义异常处理步骤

①创建异常处理器类实现HandlerExceptionResolver

在com.名字下创建一个resolver包,在包内创建MyExceptionResolver类,实现HandlerExceptionResolver接口

public class MyExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        ModelAndView modelAndView = new ModelAndView();
        if(e instanceof MyException){
            modelAndView.addObject("info","自定义异常");
        }else if(e instanceof ClassCastException){
            modelAndView.addObject("info","类转换异常");
        }
        modelAndView.setViewName("error");
        return modelAndView;
    }
    /*
        参数Exception:异常对象
        返回值ModelAndView:跳转到错误视图信息
     */
}

②在spring-mvc.xml配置异常处理器

<bean class="com.名字.resolver.MyExceptionResolver"></bean>

③编写异常页面

<body>
    <h1>通用的错误提示页面</h1>
    <h1>${info}</h1>
</body>

④测试异常跳转

1.3知识要点

异常处理方式

  • 简单异常处理器SimpleMappingExceptionResolver
  • 自定义异常处理器

自定义异常处理步骤

①创建异常处理器类实现HandlerExceptionResolver

②在spring-mvc.xml配置异常处理器

③编写异常页面

④测试异常跳转