springmvc学习笔记

基础

三层框架中的web层

mvc架构

  • 前端控制器(DispatcherServlet):流程控制的中心,管理其他组件
  • 处理器映射器(HandlerMapping):(RequestMapping)根据用户请求找到Handler(control方法)
  • 处理器适配器:
  • 处理器:controller方法
  • 视图解析器:根据逻辑地址找到物理地址,解析并渲染提交页面

mvc加载流程

  1. tomcat启动,加载web.xml
    1. 过滤器:解决post乱码问题
    2. 前端控制器:加载核心配置文件,处理所有请求
  2. 加载springmvc.xml
    1. 包扫描
    2. 配置注解驱动,创建springmvc容器:转换器、视图解析器、静态资源

mvc请求流程

  1. HTTP请求到前端控制器
  2. 前端控制器根据requestmapper寻找并执行方法
  3. 根据返回值,提交到视图解析器
  4. 视图解析器返回页面

mvc编写流程

和加载流程一致,便于理解

配置maven

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>
<!--本案例使用Tomcat进行部署,Tomcat自己有servlet-api的包,需要部署的时候排出这个包-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
    <scope>provided</scope>
</dependency>
<!--本案例使用Tomcat进行部署,Tomcat自己有jsp-api的包,需要部署的时候排出这个包-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.0</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.2</version>
</dependency>

配置web.xml

解决post中文乱码
配置前端控制器(DispatcherServlet)

<!--配置过滤器解决post的乱码问题-->
<filter>
    <!--给过滤器起名,叫啥都行-->
    <filter-name>encoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

    <!--指定过滤器的编码为UTF-8-->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>

    <!--设置乱码解决的过滤器使用-->
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<!--配置过滤器的映射,什么请求使用这个过滤器.本例就是所有请求/*-->
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <init-param>
        <!--配置加载SpringMVC的核心配置文件-->
        <!--contextConfigLocation:是固定写法,是springMVC的属性,不能改-->
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>

    <!--配置在什么时候启动SpringMVC容器-->
    <!--使用这种方式:当配置的值是大于0的正整数的时候,SpringMVC是随着Servlet容器(Tomcat)的启动而启动-->
    <!--如果为0或者这不进行配置,SpringMVC的容器是用户第一次访问的时候启动-->
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <!-- 所有的请求都会被Servlet处理 -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

配置springmvc.xml

包扫描
配置注解驱动-转换器-视图解析器

<!--包扫描-->
<context:component-scan base-package="com.alvin.controller"/>


<!--配置注解驱动-->
<!--配置转换器-->
<mvc:annotation-driven conversion-service="conversionService"/>
<!--配置转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="com.alvin.converter.DateConverter"/>
        </set>
    </property>
</bean>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>
<!--解决css静态资源的问题-->
<mvc:resources mapping="/css/**" location="/css/"/>

转换器示例代码

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 s) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date date = dateFormat.parse(s);
            return date;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

编写control

@Controller
@RequestMapping("alvin")//所有方法映射的url要加上value
public class HelloController {
    //可以只写路径,method默认get,参数默认任意
    //如果后面写参数,则参数必须一致,否则报错
    @RequestMapping(value = "/hello",method = RequestMethod.GET,params = {"id","money>100"})
    public String hello() {
        System.out.println("入门案例,执行到这里了");
        //返回xml里面指定的jsp
        return "success";
    }
}

编写web请求页面

可以提交基本类型,数组、map、pojo

<form action="/user/getUser" method="post">
    <input name="id" value="1"/>
    <input name="name" value="李白"/>
    <input name="accounts[0].id" value="0" />
    <input name="accounts[0].money" value="99999" />
    <input name="accounts[1].id" value="0"/>
    <input name="accounts[1].money" value="99999"/>
    <input name="map[nihao].id" value="1"/>
    <input name="map[nihao].money" value="111111"/>
    <input type="submit" value="post提交"/>
</form>

标题二

modelAttribute

在请求执行之前执行的方法

# 基础使用
@ModelAttribute
public void modelAttribute(Person person) {
    System.out.println(person.getUsername() + "model");
}

@RequestMapping("test")
public String test(Person person) {
    System.out.println(person.getUsername());
    return "success";
}
# 返回对象
//返回的值会保存在容器中
@ModelAttribute
public Person methodAttribute(){
    Person person = queryPerson();
    return person;
}
# 自定义存储名称
@ModelAttribute
public void methodAttribute(Map<String,Person> map){
    Person person = queryPerson();
    map.put("abc", person);
}

@RequestMapping("test")
public String test(@ModelAttribute("abc") Person person) {
    System.out.println(person);
    return "success";
}

sessionAttribute

@Controller
@SessionAttributes(value = {"username", "password"}, types = Integer.class)
@RequestMapping("sessionAttribute")
public class SessionAttributeController {
    @RequestMapping("put")
    public String putTest(Model model) {
        model.addAttribute("username", "李白");
        model.addAttribute("password", "123456");
        model.addAttribute("age", 123);
        model.addAttribute("addr", "addr");
        return "success";
    }

    @RequestMapping("get")
    public String getTest(ModelMap map) {
        System.out.println(map.get("username"));
        System.out.println(map.get("password"));
        System.out.println(map.get("age"));
        System.out.println(map.get("addr"));//不会输出
        return "success";
    }

    @RequestMapping("clean")
    public String cleanTest(SessionStatus sessionStatus) {
        sessionStatus.setComplete();
        return "success";
    }
}

restful

增post 删delete 查get 改put

  • 添加put、delete等请求的支持
<!--支持put、delete等请求-->
<filter>
    <filter-name>methodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<!--必须放在解决乱码的前面-->
<filter-mapping>
    <filter-name>methodFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  • 前端post请求必须包含_method:put,后端代码:
@RequestMapping(value = "person/{id}", method = RequestMethod.PUT)
@ResponseBody //返回的是普通数据
public String update(@PathVariable("id") int id) {
    System.out.println(id);
    return "success";
}

返回值

  • 返回string

默认会返回给视图解析器
可以通过@ResponseBody返回普通数据

  • 返回void

本质就是使用request和response

  • 返回ModelAndView
@RequestMapping("modelAndView")
public ModelAndView modelAndView() {
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("success");
    modelAndView.addObject("username", "李白");
    return modelAndView;
}

转发和重定向

@RequestMapping("testForward")
public String testForward(){
    //使用forward关键词完成请求转发,到success.jsp成功页
    return "forward:/WEB-INF/jsp/success.jsp";
}

@RequestMapping("testRedirect")
public String testRedirect(){
    //使用redirect关键词完成请求重定向,到第一个testString方法
    return "redirect:testString";
}

json

请求必须是json!!!JSON.stringify(rowData)

  • 应用
<!--支持json格式数据交互的依赖-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.5</version>
</dependency>
  • 使用
public @ResponseBody Person test(@RequestBody() Person person) {
    return person;
}

文件上传

  • 引入
<!--支持文件上传的组件-->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>
<!--跨服务器文件上传的支持-->
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-core</artifactId>
    <version>1.18.1</version>
</dependency>
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-client</artifactId>
    <version>1.18.1</version>
</dependency>
  • 配置文件解析器
<!--配置文件上传解析器-->
<!--上传解析器的id必须是接口名,首字母消息-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--配置上传文件的大小不能超过1M-->
    <property name="maxUploadSize" value="1048576"/>
</bean>
  • 使用
# 上传到本地服务器

public String upload(MultipartFile uploadFile, String fileName) throws IOException {
    uploadFile.transferTo(new File("D:/alvin/1.jpg"));
    //返回成功页面
    return "success";
}

# 上传到其他服务器
# 修改要上传服务器tomcat的web.xml
<init-param>
    <param-name>readonly</param-name>
    <param-value>false</param-value>
</init-param>
------------------------------------

String imageUrl = "http://127.0.0.1:9090/uploads/"
//使用jersey进行上传
Client client = Client.create();
//执行上传的路径
WebResource resource = client.resource(imageUrl + fileName);
//执行上传
resource.put(String.class,uploadFile.getBytes());

异常处理

  • 自定义error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
自定义异常!!!
</body>
</html>

  • 自定义异常
public class MyException extends Exception {
    public MyException(String message) {
        super(message);
    }
}

  • 自定义全局异常
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyHandleExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        MyException myException = null;
        if (ex instanceof MyException) {
            myException = (MyException) ex;
        } else {
            myException = new MyException("运行异常,请找管理员");
        }
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg", myException.getMessage());
        modelAndView.setViewName("error");
        return modelAndView;
    }
}
  • 配置全局异常处理器(springmvc.xml)
<!--全局异常处理-->
<bean class="com.alvin.ex.MyHandleExceptionResolver"/>
  • 正常使用即可
int a = 1 / 0;

Interceptor拦截器

与filter区别:
interceptor只能springmvc使用,filter属于servlet;
interceptor只能拦截方法,filter可以拦截所有。

  • 自定义拦截器
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        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("after");
    }
}

  • 注册

springmvc.xml

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/test/**"/>
        <bean class="com.alvin.interceptor.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>
原文地址:https://www.cnblogs.com/birdofparadise/p/10012285.html