SpringMVC框架学习笔记

第一个SpringMVC程序

配置文件

springmvc.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="cn.test.handler"/>

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

​ web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <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:springmvc.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>
</web-app>

​ Handler.java

@Controller
public class Handler {

    @RequestMapping("welcome")
    public String Welcome(){
        return "success";
    }
}

​ index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <a href="${pageContext.request.contextPath}/welcome">I'm welcome</a><br>
  </body>
</html>

​ success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>I'm success.jsp</h1>
</body>
</html>

HiddenHttpMethodFilter过滤器

​ 给 普通浏览器 增加 put|delete请求方式

​  ​ ​ ​HiddenHttpMethodFilter过滤器拦截请求的要求:

​  ​ ​ ​ ​ ​ ​1.<input type=“hidden” name="_method" value=“delete/put”/>

​  ​ ​ ​ ​ ​ ​2.请求方式为post

传值方式

url传值@PathVariable

    //通过url传值
    @RequestMapping("welcome2/{name}")
    public String Welcome2(@PathVariable("name") String name){
        System.out.println(name);
        return "success";
    }

普通表单传值@RequestParam(等价于request.getParameter())

    //普通表单传值(可接受多个参数)
    @RequestMapping("testDelete")
    public String TestDelete(@RequestParam("uname") String name, @RequestParam(value = "uid", required = false, defaultValue = "18") int id){
        System.out.println("删: "+id+" "+name);
        return "success";
    }

实体类对象自动传值(表单中的参数名要和实体类的属性名相同)

Handler.java

    @RequestMapping("testObjectProperties")
    public String TestObjectProperties(Student student){
        System.out.println(student);
        return "success";
    }

index.java

  <form action="${pageContext.request.contextPath}/testObjectProperties">
    sid:<input type="text" name="sid"><br>
    sname:<input type="text" name="sname"><br>
    homeAddress:<input type="text" name="address.homeAddress"><br>
    schoolAddress:<input type="text" name="address.schoolAddress">
    <input type="submit" value="提交">
  </form>

Student.java

public class Student {
    private int sid;
    private String sname;
    private Address address;//Address包含homeAddress、schoolAddress两属性
    
    getter、setter方法省略
}

处理模型数据(跳转时携带数据)

 ​ ​ ​将数据放在request 域

Handler.java

    //ModelAndView既有数据又有视图
    @RequestMapping("testModelAndView")
    public ModelAndView TestModelAndView(){
        ModelAndView mv = new ModelAndView("success"); //会自动加上前后缀
        Student  stu = new Student();
        stu.setSid(1);
        stu.setSname("zs");
        mv.addObject("student", stu);//相当于request.setAttribute("student", stu);
        return mv;
    }

    //传入模型返回视图
    @RequestMapping("testModelAndView2")
    public String TestModelAndView2(ModelMap model){

        Student  stu = new Student();
        stu.setSid(1);
        stu.setSname("zs");
        model.put("student2", stu);//相当于request.setAttribute("student", stu);
        return "success";
    }

jsp页面获取值

${requestScope.student.sid}
${requestScope.student.sname}

将数据放在 session 域

Handler.java

@SessionAttributes(value = {"student", "student2"})
或者
@SessionAttributes(types = Student.class)

jap获取值

    ${sessionScope.student.sid}
    ${sessionScope.student.sname}

数值更新 ModelAttribute //先查询再修改

	//模拟查询过程
	@ModelAttribute//慎用! 任意一次请求执行前,都会执行@ModelAttribute修饰的方法
	//@ModelAttribute 在请求该类的各个方法前均被执行的设计给予一个思想:一个控制器只做一个功能
    public void queryStudent(Map<String, Object> map){
        Student student = new Student();
        student.setSid(1);
        student.setSname("zs");
        map.put("student", student);//约定:map中key是下面方法参数类型的首字母小写
        													student-Student
    }		//不过不一致也可以map.put("stu", student) 下面方法参数@ModelAttribute("stu")

    @RequestMapping("testModelAttribute")
    public String TestModelAttribute(Student stu){
        stu.setSname(stu.getSname());
        System.out.println(stu);
        return "success";
    }

视图、视图解析器

视图的顶级接口:View

视图解析器:ViewResolver

常见的视图和解析器:

 ​ ​ ​InternalResourceView、InternalResourceViewResolver

SpringMVC解析jsp时,会默认使用InternalResourceView,但如果发现Jsp中包含了jstl语言,会自动转为JstlView,JstlView可以解析jstl 实现国际化操作(国际化:针对不同地区、不同国家,进行不同的显示)

​  ​ ​ ​public class JstlView extends InternalResourceView(){}


实现国际化具体步骤:

1.创建资源文件

​  ​ ​ ​基名_语言_地区.properties or 基名_语言.properties

i18n_en.US.properties

resource.welcome=WELCOME
resource.exit=EXIT

i18n_en.US.properties

resource.welcome=欢迎
resource.exit=退出

2.配置springmvc.jsp文件

    <!--  加载国际化资源文件(id名必须为messageSource)  -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="i18n"/>
    </bean>

3.通过jstl使用国际化

​  ​ ​ ​导入jstl.jar、standard.jar包


InternalResourceViewResolver其他功能

1.实现不通过Controller直接index.jsp→success.jsp

​  ​ ​ ​前面index.jsp→Controller(@RequestMapping)→success.jsp

springmvc.xml

    <mvc:view-controller path="testMvcViewController" view-name="success"/>

但是该配置会让所有请求转入该配置中的映射地址,而忽略掉@RequestMapping(),若要两者共存,则需

	<mvc:annotation-driven/>

2.指定请求方式

​ SpringMVC默认的跳转方式为请求转发,若需改为重定向则需:

    @RequestMapping("testRedirect")
    public String TestRedirect(){
        return "redirect:/views/success.jsp";
        //注意 此方式不会被视图解析器加上前缀和后缀,需手动添加
    }

3.处理静态资源

​  ​ ​ ​静态资源:html、css、js、图片、视频等等

​  ​ ​ ​动态资源:可以与用户交互、因为时间、地点的不同而结果不同的内容,如百度天气不同地方的结果不同

​  ​ ​ ​在SpringMVC中若直接访问静态资源:404,原因:之前将所有的请求通过通配符“/”拦截,进而交给SpringMVC的入口DispatcherServlet去处理:去找请求映射对应的@RequestMapping或配置文件中的<mvc:path…/>

​  ​ ​ ​解决方法:

 ​ ​ ​ ​ ​ ​若请求不需要SpringMVC处理,则使用tomcat默认的servlet去处理:若有对应的拦截请求,则交给对应的Servlet去处理,如果没有默认的servlet,则直接访问。tomcat默认servlet位置:cong\web.xml

<!--  让SpringMVC在接到没有对应@RequestMapping的请求时时, 将请求交给服务器默认的servlet去处理  -->
<mvc:annotation-driven/>
<mvc:default-servlet-handler/>
<mvc:resources mapping="/img/**" location="/img/"/>//图片路径:img\joey.jpg


4.类型转换

​  ​ ​ ​a.SpringMVC内置了一些常见的类型转换器

​  ​ ​ ​b.自定义类型转换器(下面以String→Student转换为例)

 ​ ​ ​ ​ ​ ​i.编写自定义类型转换器的类(实现Converter接口)

public class MyConverter implements Converter<String, Student> {

    @Override
    public Student convert(String source) {
        //source: 2-zs
        String[] arr = source.split("-");
        Student stu = new Student();
        stu.setSid(Integer.parseInt(arr[0]));
        stu.setSname(arr[1]);
        return stu;
    }
}

 ​ ​ ​ ​ ​ ​ii.配置自定义转换器(三大步)

    <!-- 1.将自定义转换器纳入SpringIOC容器 -->
    <bean id="myConverter" class="cn.test.converter.MyConverter"/>

    <!-- 2.将自定义转换器myConverter纳入SpringMVC提供的转换器Bean中 -->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set><ref bean="myConverter"/> </set>
        </property>
    </bean>

    <!-- 3.将conversionService注册到annotation-driven中 -->
    <mvc:annotation-driven conversion-service="conversionService"/>

 ​ ​ ​ ​ ​ ​iii.测试

Handler.java

    @RequestMapping("testConverter")
    public String TestConverter(@RequestParam("studentInfo") Student student){
        System.out.println(student);
        return "success";
    }

index.jsp

  <form action="${pageContext.request.contextPath}/testConverter" method="post">
    学生信息:<input name="studentInfo" type="text">
    <input type="submit" value="转换">
  </form>


5.数据格式化

 ​ ​ ​以前:SimpleDateFormat sdf = new SimpleDateFormat (“yyyy-MM-dd hh:mm:ss”);

 ​ ​ ​SpringMVC提供了很多注解,方便实现数据格式化

日期格式化实现步骤

​  ​ ​ ​a.在springmvc.xml中配置

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionService"/>

​  ​ ​ ​b.在Student.java中对属性增加注解

    //格式化前端传来的数据
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthDay;

​  ​ ​ ​c.Handler.java

    @RequestMapping("testDateFormat")
    public String TestDateFormat(Student student, BindingResult result){
	//约定 第二个参数BindingResult可直接异常报告,相当于try/catch
        if(result.getErrorCount()>0){
            for (ObjectError error: result.getAllErrors()){
                System.out.println(error);
            }
        }

        System.out.println(student);
        System.out.println(student.getBirthDay());

        return "success";
    }

​  ​ ​ ​d.index.jsp

  <form action="${pageContext.request.contextPath}/testDateFormat" method="post">
    sid:<input type="text" name="sid"><br>
    sname:<input type="text" name="sname"><br>
    birthDay:<input type="text" name="birthDay"><br>
    <input type="submit" value="提交">
  </form>

数字格式化(其他与日期格式化相同,除了在Student.java页面增加的注解不一样):

    @NumberFormat(pattern = "###,#")
    private int sid;

 ​ ​ ​其中上面配置springmvc.xml用到的FormattingConversionServiceFactoryBean既可以实现格式化、也可以实现类型转下,以后实现类型转换可以直接在FormattingConversionServiceFactoryBean里面写

前端展示错误信息(将错误消息放入request域)

Handler.java

    @RequestMapping("testDateFormat")
    public String TestDateFormat(Student student, BindingResult result, Map<String, Object> map){
        //约定 第二个参数BindingResult可直接异常报告,相当于try/catch
        //参数位置不可随便更换,因为这是框架规定好的
        if(result.getErrorCount()>0){
            for (ObjectError error: result.getFieldErrors()){
                System.out.println(error.getDefaultMessage());
                map.put("errors", error.getDefaultMessage());
            }
        }
        System.out.println(student);
        System.out.println(student.getBirthDay());
        return "success";
    }

success.jsp

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<c:forEach items="${errors}" var="error">
	${error}
</c:forEach>



数据检验

 ​ ​ ​JSP303、Hibernate Validator

使用Hibernate Validator步骤:

1.导入jar包(注意jar包之间的版本兼容问题

​  ​ ​ ​hibernate validator.jar

​  ​ ​ ​classmate.jar

​  ​ ​ ​jboss-logging.jar

​  ​ ​ ​validation-api.jar

​  ​ ​ ​hibernate-validator-annotation-processor.jar

2.配置springmvc.xml

​  ​ ​ ​要实现JSP303、Hibernate Validator或其他校验,必须实现SpringMVC提供的一个接口:ValidatorFactory

 ​ ​ ​而LocalValidatorFactoryBean是ValidatorFactory的一个实现类,<mvc:annotation-driven/>会自动加载LocalValidatorFactoryBean类,因此可以直接实现数据校验。

<mvc:annotation-driven/>

3.使用

Student.java

    @Past//需要一个过去的时间
    @DateTimeFormat(pattern = "yyyy-MM-dd")//前端输入日期需符合该格式
    private Date birthDay;

Handler.java(在被检验的参数Student前加@Valid)

    @RequestMapping("testDateFormat")
    public String TestDateFormat(@Valid Student student, BindingResult result, Map<String, Object> map){
        //约定 第二个参数BindingResult可直接异常报告,相当于try/catch
        System.out.println(student);
        System.out.println(student.getBirthDay());

        if(result.getErrorCount()>0){
            for (ObjectError error: result.getFieldErrors()){
                System.out.println(error.getDefaultMessage());
                map.put("errors", error.getDefaultMessage());
            }
        }

        return "success";
    }



Ajax请求SpringMVC,并且返回JSON数据

1.导入jar包(注意版本要一致)

​  ​ ​ ​jackson-annotations.jar

​  ​ ​ ​jackson-core.jar

​  ​ ​ ​jackson-databind.jar

2.用@ResponseBody修饰方法

​  ​ ​ ​@ResponseBody修饰的方法,会将该方法的返回值以一个json数组的形式返回给前端

    @ResponseBody
    @RequestMapping("testJson")
    public List<Student> testJson(){
        //Controller -> Service -> Dao
        //但是现在省略这些步骤,假装已经直接拿到了对象数据
        Student stu1 = new Student(1, "zs");
        Student stu2 = new Student(2, "ls");
        Student stu3 = new Student(3, "ww");

        List<Student> students = new ArrayList<>();
        students.add(stu1);
        students.add(stu2);
        students.add(stu3);
        return students;
    }

3.前端将返回值结果以json数组的形式传给了result

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Index</title>
    <%-- 引入jquery --%>
    <script type="text/javascript" src="js/jquery-3.2.1.js"></script>
    <script type="text/javascript">
      $(document).ready(function () {
        $("#testJson").click(function () {
            //通过ajax请求springmvc
            $.post(
                    "testJson",//服务器地址
                    // {
                    //   "sid" : 5,
                    //   "sname" : "zs",
                    // },
                    function (result) { //服务端处理完毕后的回调函数
                        for(var i=0; i<result.length; i++){
                          alert(result[i].sid+"-"+result[i].sname);
                        }
                    }

            )
        })
      })
    </script>

  </head>
  <body>
  <%--按钮--%>
  <input type="button" value="testJson" id="testJson">
  </body>



SpringMVC实现文件上传

​  ​ ​ ​和Servlet本质一样,都是通过commons-fileupload.jar和commons-io.jar

​  ​ ​ ​SpringMVC可以简化文件上传的代码,但是必须满足条件:实现MultipartResolver接口,SpringMVC也提供了该类的实现类CommonsMultipartResolver

实现步骤:

​ ​ ​ ​ 1.导入jar包(commons-fileupload.jar、commons-io.jar)

 ​ ​ ​​ 2.配置,将CommonsMultipartResolver加入SpringIOC容器中(可直接在springmvc.xml中配置)

<!-- 配置CommonsMultipartResolver,用于实现文件上传,将其加入SpringIOC容器,id值唯一,不能改变 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<!-- 文件编码 -->
	<property name="defaultEncoding" value="UTF-8"/>
	<!-- 上传单个文件的最大值, 单位Byte, 如果值为-1, 表示无限制-->
	<property name="maxUploadSize" value="102400"/>
</bean>

​  ​ ​ ​3.处理方法

Handler.java

    @RequestMapping("testUpload")
    public String testUpload(@RequestParam("describe") String describe,@RequestParam("file") MultipartFile file) throws IOException {
        System.out.println(describe);
        //jsp中上传的文件:file
        InputStream input = file.getInputStream();
        String fileName = file.getOriginalFilename();

        //将file上传到服务器中的某一个硬盘文件中
        OutputStream output = new FileOutputStream("C:\\Users\\yaoweungyu\\Desktop\\"+fileName);
        byte[] bs = new byte[1024];
        int len = -1;
        while ((len = input.read(bs)) != -1){
            output.write(bs, 0 ,len);
        }

        output.close();
        input.close();
        System.out.println("上传成功");

        return "success";
    }

index.jsp

  <form action="${pageContext.request.contextPath}/testUpload" method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    文件描述信息:<input type="text" name="describe">
    <input type="submit" value="上传">
  </form>



拦截器

​  ​ ​ ​拦截器的原理和过滤器相同。

​  ​ ​ ​在SpringMVC要想实现拦截器,需要实现一接口HandlerInterceptor

实现步骤:

​  ​ ​ ​1.编写拦截器implements HandlerInterceptor

​ ​ ​ ​ 2.配置:将自己写的拦截器配置到springmvc.xml中(spring)

    <!--  配置拦截器 默认拦截全部请求 -->
    <mvc:interceptors>
        <!-- 第一个拦截器  -->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/testObjectProperties"/>
            <bean class="cn.test.interceptor.MyInterceptor"/>
        </mvc:interceptor>

        <!-- 第二个拦截器  -->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/testObjectProperties"/>
            <bean class="cn.test.interceptor.MySecondInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

​ ​ ​ ​ 3.测试

Handler.java

    @RequestMapping("testInterceptor")
    public String testInterceptor(){
        System.out.println("----我是请求处理方法----");
        return "success";
    }

控制台输出

第一个拦截器 拦截请求
第二个拦截器 拦截请求
----我是请求处理方法----
第二个拦截器 拦截响应
第一个拦截器 拦截响应
第二个拦截器 视图渲染完毕
第一个拦截器 视图被渲染完毕



异常处理

​ ​ ​ ​ HandlerExceptionResolver接口

​  ​ ​ ​HandlerExceptionResolver接口的每个实现类都是处理异常的一种方式

如:

1.ExceptionHandlerExceptionResolver类

​  ​ ​ ​主要提供了注解@ExceptionHandler,并通过该注解处理异常

    //该方法可以自动捕获 本类中 抛出的以下参数中的类型的异常(处理路径:最短优先)
    @ExceptionHandler({ArithmeticException.class, ArrayIndexOutOfBoundsException.class})
    public ModelAndView testArithmeticException(Exception e){
        ModelAndView mv = new ModelAndView("error");
        System.out.println(e);
        mv.addObject("error", e);
       return mv;
    }

 ​ ​ ​处理 不在同一个类中 的异常,需给处理异常的类加@ControllerAdvice,并实现HandlerExceptionResolver接口

@ControllerAdvice
public class MyExceptionHandler implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("error", ex);
        System.out.println(ex);
        return mv;
    }
}

2.ResponseStatusExceptionResolver类

​ ​ ​ ​提供注解@ResponseStatus,实现自定义异常显示页面

 ​ ​ ​在类前加注解@ResponseStatus实现自定义异常显示页面还需要继承Exception类

@ResponseStatus(value = HttpStatus.FORBIDDEN, reason = "你的数组越界了啦!~")
public class MyArrayIndexOutOfBoundsException extends Exception{
}

 ​ ​ ​也可以在方法前加注解@ResponseStatus实现自定义异常显示页面

    @RequestMapping("testMyArrayIndexOutOfBoundsException")
    public String testMyArrayIndexOutOfBoundsException(@RequestParam("i") int i){
        if(i==3){
            return "redirect:MyArrayIndexOutOfBoundsException";
        }
        return "success";
    }

    @ResponseStatus(value = HttpStatus.FORBIDDEN, reason = "你的数组越界了啦!~")
    @RequestMapping("MyArrayIndexOutOfBoundsException")
    public void MyArrayIndexOutOfBoundsException(){

    }

3.DefaultHandlerExceptionResolver类

​  ​ ​ ​SpingMVC在一些常见的异常基础上(300、500、404),新增了一些异常,例如:

 * @see #handleNoSuchRequestHandlingMethod
 * @see #handleHttpRequestMethodNotSupported
 * @see #handleHttpMediaTypeNotSupported
 * @see #handleMissingServletRequestParameter
 * @see #handleServletRequestBindingException
 * @see #handleTypeMismatch
 * @see #handleHttpMessageNotReadable
 * @see #handleHttpMessageNotWritable
 * @see #handleMethodArgumentNotValidException
 * @see #handleMissingServletRequestParameter
 * @see #handleMissingServletRequestPartException
 * @see #handleBindException

4.SimpleMappingExceptionResolver类:

​  ​ ​ ​通过配置实现异常的处理

    <!--  通过配置处理异常  -->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <!-- 如果发生异常,异常对象会被保存在exceptionAttribute的value值中,默认值为exception -->
        <property name="exceptionAttribute" value="ex"/>
        <property name="exceptionMappings">
            <props>
                <!-- 相当于catch(ArithmeticException e)然后跳转到error页面 -->
                <prop key="java.lang.ArithmeticException">
                    error
                </prop>
            </props>
        </property>
    </bean>

发布了46 篇原创文章 · 获赞 1 · 访问量 2398

猜你喜欢

转载自blog.csdn.net/weixin_43708069/article/details/104665444
今日推荐