Fork me on GitHub

SpringMVC笔记

系列二来了…这次是SpringMVC

写此系列的目的是做一个学习笔记管理,方便以后复习用。

Spring集成web环境

原理:

  1. 添加坐标 servlet和jsp
  2. 添加web层servlet,在web.xml配置servlet
  3. web通过spring容器获取Service对象—–在web项目中通过ServletContextListener监听Web应用的活动,在web应用启动时,加载spring配置文件,创建上下文对象ApplicationContext,将其存储到最大的与servletContext域中,这样就可以在任意位置从域中获取ApplicationContext对象了。(web.xml配置监听器)

步骤

  1. 配置ContextLoaderListener监听器

    1
    2
    3
    4
    5
    6
    7
    8
    9
     <!--全局化初始参数-->
    <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>
  2. 使用WebapplicationcontextUtils获取应用上下文

    1
    2
    3
    4
    ServletContext servletContext = this.getServletContext();
    ApplicationContext app = (ApplicationContext) WebApplicationContextUtils.getWebApplicationContext(servletContext);
    UserService userService = app.getBean(UserService.class);
    userService.save();

快速入门

  1. 导入坐标

    1
    2
    3
    4
    5
    6
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
    <!--<scope>provided</scope>疑问导入spring-web包时加了范围会出错-->
    </dependency>
  2. 配置核心控制器DispatcherServlet web.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <!--配置springmvc的前端控制器-->
    <servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--加载servlet时加载配置文件-->
    <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类和视图页面,注入Spring容器

    1
    2
    3
    4
    5
    6
    7
    8
    @Controller
    public class UserController {
    @RequestMapping("/quick")//访问路径
    public String save(){
    System.out.println("controller running");
    return "success.jsp";
    }
    }
  4. 使用注解配置Controller类中业务方法的映射地址

  5. 配置SpringMVC核心文件spring-mvc.xml

    配置扫描组件,和context空间

    1
    2
    3
    4
    5
    6
    7
    <!--Controller组件扫描-需要加载context空间-->
    <context:component-scan base-package="com.tsuki.controller"/>

    <!--配置组件扫描,小tip,可以设置扫或者不扫-->
    <context:component-scan base-package="com.tsuki">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
  6. 客户端发起请求测试

    访问路径”/quick”

相关组件

DispathcherServlet; HandlerMapping; HandlerAdapter; Handler; View Resolver; View;

  • 注解解析

    1. @RequestMapping: URL与处理请求的方法之间建立联系

    ​ 参数: value,method(RequestMethod.POST), params

    1. 视图解析器配置: 有默认配置—-可以指定功能进行增强–配置内部资源视图解析器 redirect和forward

      1
      2
      3
      4
      5
      <!--配置内部资源视图解析器,但是这样做不好阅读啊(小疑问),而且做了代码内部修改-->
      <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="prefix" value="/jsp/"></property>
      <property name="suffix" value=".jsp"></property>
      </bean>

SpringMVC的请求和响应

数据响应的方式

1. 页面跳转

  1. 返回字符串–参见快速入门, prefix + String + suffix 代表页面跳转

  2. 返回ModelAndView

    save()参数还可以是HttpServletRequest等官方的定义,但是不建议使用,model和view可以拆开使用也可以一起使用,可以new也可以作为形参传入。

    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
    @RequestMapping("/quick4")
    public String save4(Model model){
    model.addAttribute("username", "lisi");
    return "success.jsp";
    }

    @RequestMapping("/quick3")
    public ModelAndView save3(ModelAndView modelAndView){
    modelAndView.setViewName("success.jsp");
    modelAndView.addObject("username", "zhangsan");
    return modelAndView;
    }

    @RequestMapping("/quick2")
    public ModelAndView save2(){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("success.jsp");
    modelAndView.addObject("username", "helloworld");
    return modelAndView;
    }

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

2. 回写数据

  1. 直接返回字符串 @ResponseBody

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @RequestMapping("/quick6")
    @ResponseBody
    public String save6() throws JsonProcessingException {
    User user = new User();
    user.setUsername("henry");
    user.setAge(30);
    ObjectMapper objectMapper = new ObjectMapper();
    String json = objectMapper.writeValueAsString(user);//jackson进行转换
    return json;
    }
  1. 返回对象和集合–设置将对象转换为json对象输出(配置处理器映射器)—可以通过mvc的注解替代以上操作

    spring-mvc.xml, 同时要加入springmvc的命名空间,就可以不需要json转换工具了

    1
    2
    3
    4
    5
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation=" http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"

    <!--mvc的注解驱动-->
    <mvc:annotation-driven/>

数据请求

1. 实现数据请求方式

  • 基本数据类型参数

  • POJO类型参数

  • 数组类型参数

    1
    2
    3
    4
    5
    6
    //localhost/Springdemo/quick8?strs='111'&strs='222'
    @RequestMapping("/quick8")
    @ResponseBody
    public void save8(String[] strs){
    System.out.println(Arrays.asList(strs));
    }

    以上三种都比较简单,只要名称一致框架就会自动封装

  • 集合类型参数

    1. 将集合包装到一个POJO中

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      public class VO {
      private List<User> userList;
      //提供get 和set
      }
      //VO作为形式参数
      @RequestMapping("/quick10")
      @ResponseBody
      public void save10(VO vo){
      System.out.println(vo);
      }
      //此处要求VO中的属性名称和表单提交的名称一致
      <input type="text" name="userList[0].username"><br/>
  1. ajax请求时指定contextType为json,使用

    @RequestBody

    访问jQuery失败:

    1
    2
    <!--开发资源的访问 spring-mvc.xml, 开放静态资源的访问-->
    <mvc:default-servlet-handler/>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var userList = new Array();
    userList.push({username:"zhangsan", age:12});
    userList.push({username: "lisi", age: 15});

    $.ajax({
    type:"POST",
    url:"${pageContext.request.contextPath}/quick9",
    data:JSON.stringify(userList),//将数组转为json数据
    contentType: "application/json; charset=utf-8"
    });
    1
    2
    3
    4
    5
    @RequestMapping("/quick9")
    @ResponseBody
    public void save9(@RequestBody List<User> userList){
    System.out.println(userList);
    }

2. 获取数据细节

  • 中文乱码问题

  • @RequestParam (value, required, defaultValue)和 @PathVariable

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //localhost/quick11?name=zhangsan
    @RequestMapping("/quick11")
    @ResponseBody
    public void save11(@RequestParam("name") String username){
    System.out.println(username);
    }
    //localhost/quick11?username=zhangsan
    @RequestMapping("/quick12/{username}")
    @ResponseBody
    public void save12(@PathVariable("username") String username){
    System.out.println(username);
    }
  • 自定义类型转换器–

    • 定义com.tsuki.converter.DateConverter实现Converter接口
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package com.tsuki.converter;


    import org.springframework.core.convert.converter.Converter;//注意不要导错包

    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;

    public class DateConverter 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;
    }
    }
    • 在配置文件中声明转换器,在 <annotation-driven> 中引用转换器。spring-mvc.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <!--mvc的注解驱动-->
    <mvc:annotation-driven conversion-service="conversionService"/>

    <!--开发资源的访问-->
    <mvc:default-servlet-handler/>
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
    <list>
    <bean class="com.tsuki.converter.DateConverter"></bean>
    </list>
    </property>
    </bean>
  • 获取Servlet相关API:直接形参注入

  • @RequestHeader和@CookieValue

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @RequestMapping("/quick14")
    @ResponseBody
    public void save14(@CookieValue(value = "JSESSIONID", required = false) String user_agent){
    System.out.println(user_agent);
    }

    @RequestMapping("/quick13")
    @ResponseBody
    public void save13(@RequestHeader(value = "User-Agent", required = false) String user_agent){
    System.out.println(user_agent);
    }
  • 文件上传

    • 表单编写

      1
      2
      3
      4
      5
      6
      <%--注意enctype的填写--%>
      <form action="${pageContext.request.contextPath}/quick15" method="post" enctype="multipart/form-data">
      名称<input type="text" name="username"><br/>
      文件<input type="file" name="uploadFile"><br/>
      <input type="submit" value="提交">
      </form>
    1. pom.xml导入坐标

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
      </dependency>
      <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.6</version>
      </dependency>
    2. 配置文件上传解析器 spring-mvc.xml

      1
      2
      3
      4
      5
      <!--配置文件上传解析器-->
      <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
      <property name="defaultEncoding" value="UTF-8"/>
      <property name="maxUploadSize" value="500000"/>
      </bean>
    3. 编写文件上传代码

      1
      2
      3
      4
      5
      6
      7
      8
      9
      @RequestMapping("/quick15")
      @ResponseBody
      public void save15(String username, MultipartFile uploadFile) throws IOException {
      //uploadFile形参名字与表单的提交文件name名称一致
      System.out.println(username);
      String originalFilename = uploadFile.getOriginalFilename();
      //保存到某位置
      uploadFile.transferTo(new File("F:\\图片\\"+originalFilename));
      }

拦截器

  • 快速入门

    1. 创建拦截器实现HandlerInterceptor接口

      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
      public class MyInterceptor1 implements HandlerInterceptor {
      //目标方法执行之前 执行
      @Override
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      System.out.println("preHandle running...");
      String param = request.getParameter("param");
      if("yes".equals(param)){
      return true;
      }else{
      request.getRequestDispatcher("success.jsp").forward(request,response);
      return false;
      }
      }
      //目标方法执行之后,视图对象返回之前执行
      @Override
      public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
      modelAndView.addObject("name", "Java");
      System.out.println("postHandle running...");
      }
      //在流程都执行完毕后执行
      @Override
      public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
      System.out.println("aftercomletion running...");
      HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
      }
      }
    2. 配置拦截器 spring-mvc.xml

      1
      2
      3
      4
      5
      6
      7
      8
      <!--配置拦截器-->
      <mvc:interceptors>
      <mvc:interceptor>
      <!--对那些资源进行拦截-->
      <mvc:mapping path="/**"/>
      <bean class="com.tsuki.interceptor.MyInterceptor1"/>
      </mvc:interceptor>
      </mvc:interceptors>
  1. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Controller
    public class TargetController {
    @RequestMapping("/target")
    public ModelAndView show(){
    System.out.println("target is running...");
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("name", "Tomcat");
    modelAndView.setViewName("index.jsp");
    return modelAndView;
    }
    }

登录验证案例(待实践)

过滤器:

  1. 获取session对象 request.getSession().getAttribute(“user”)
  2. 判断是否有user,否(return false) 是 (return true)

登录:

  1. login(username, password){} 调用userService.login():返回User(查表并用jdbcTemplate接收)
  2. 判断user是不是空,有(存到Session,并跳转首页) 否(跳转到登录页面)

异常处理

配合日志输出使用

1
2
3
4
5
6
7
8
9
<!--配置异常处理器-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView" value="error.jsp"/>
<!--<property name="exceptionMappings">
<map>
<entry key="异常类型" value="错误视图">
</map>
</property>-->
</bean>

自定义异常处理

1. 创建异常处理器类实现HandlerExceptionResolver
 2. 配置异常处理器到spring-mvc.xml
 3. 编写异常页面

JdbcTemplate(待补充)

补充

SimpleDateFormat中有两个方法,parse()和format()

parse()把String型的字符串转换成特定格式的date类型

format()把Date型的字符串转换成特定格式的String类型

equals:参考博客

public boolean equals(Object obj) { return (this == obj); }

运行问题

  1. 报错1:Servlet不能正常访问,错误代码500,原因在于版本,我原本用的是tomcat10,改成tomcat9之后成功解决。论版本兼容的重要性。tomcat各版本的兼容
  2. 创建web项目还是不熟练。教程
  3. 本来Servlet要注入到web.xml中才会运行的,但是不知道什么原因不需注入也可以访问到。
  4. SpringMVC错误:org.springframework.web.servlet.DispatcherServlet noHandlerFound ,我的错误原因是访问静态资源,改为访问jsp就成功了
  5. 在导入了jackson的坐标后发生了新的错误:java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/exc/InvalidDefinitionException ,找到问题了,版本不兼容,致命
  6. 在测试jsp页面发出post请求,用$.ajax响应集合类型参数是出现找不到jQuery和访问路径/quick的情况,原因是路径问题。url:"${pageContext.request.contextPath}/quick9", 是jsp获取绝对路径的方式,这篇博客解析
  7. SpringMVC中已经配置了解决中文乱码问题的过滤器后,还会出现中文乱码现象,尝试了博客所述的方法但是还未解决乱码问题,但是使用maven发布时不会乱码


本文标题:SpringMVC笔记

文章作者:tsuki

发布时间:2021.12.24 - 16:27

最后更新:2021.12.27 - 19:52

原始链接:https://tsuki419.github.io/SpringMVC.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------THE END-------------
0%