欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring MVC

程序员文章站 2022-06-13 21:01:42
...

spring mvc

用来开发基于web的应用程序;

  1. 主流的mvc框架
  • struts 1.x
  • webwork
  • Struts 2.x(webwork+struts 1.x)
  • springmvc 更容易上手,相对安全;
  1. mvc思想
  • model模型 数据domain
  • view视图 数据的展现方式 jsp、jstl、el
  • controller控制器 结合模型和视图 控制请求流程 servlet、controller

servlet作为控制器的缺点:

  • 请求参数处理麻烦
  • 当业务比较多时,servlet类的数量膨胀不好管理
    controller优点:
  • 可以利用spring中各种思想,提高了程序的可扩展性;

spring mvc要做的事情

  • 将url映射到Java类或Java类的方法;
  • 封装用户提交的数据;
  • 处理请求——调用相关的业务处理——封装相应的数据;
  • 将响应数据进行渲染;

Spring MVC

spring mvc使用

  1. 添加依赖
<dependencies>
        <!-- spring mvc 依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.21.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.21.RELEASE</version>
        </dependency>

        <!-- servlet, jsp, 标签库 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.2.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
  1. 添加spring配置文件spingmvc.cml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

        <!--扫描控制器类-->
        <mvc:annotation-driven/>
        <!--扫描控制器类-->
        <context:component-scan base-package="com.westos.controller"/>
    
    
</beans>
  1. 添加控制器
    spring提供的前控制器 DispatcherServlet (实际上是一个servlet):作为一个统一入口,请求先进入这个入口,由它来分发请求,进入真正的控制器;
    Spring MVC
    需要使用web.xml文件配置它的路径;
    file-project Structure
    生成web.xml文件
    Spring MVC
  • 配置前控制器
<?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>
        <servlet-name>s</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        
        <!--指明spring配置文件的位置 根据它创建spring容器-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!--tomcat启东市,就创建和初始化sevlet,同时创建spring容器-->
        <!--1表示优先级-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>s</servlet-name>
        <!--用来匹配所有路径-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
  • 自定义的控制器
@Controller
public class 控制器类{
	
	//在web的请求路径和java代码之间建立映射关系,以方法为单位进行映射
	@RequestMapper("请求路径") //请求路径不能重复
	public void 方法1(){
	}
	
	@RequestMapper("请求路径")
	public void 方法2(){
	}
}
@Controller
public class HelloController {

    @RequestMapping("/m1")
    public String m1(){
        return "hello";
    }

    @RequestMapping("/m2")
    public String m2(){
        return "hello2";
    }


}
  1. 添加视图
@Controller
public class 控制器类{

	@RequestMapper("请求路径") //请求路径不能重复
	public String 方法1(){
		return "hello"//返回值代表视图名字,但是注意它不是完整路径
	}
	
	@RequestMapper("请求路径")
	public void 方法2(){
	}
}

配置视图的完整路径
springmvc.xml

        <!--配置视图的完整路径(前缀 后缀) 配置视图解析器-->
        <mvc:view-resolvers>
                <!--将请求视图路径补充完整 再利用请求转发跳至jsp-->
                <mvc:jsp prefix="/" suffix=".jsp"/>
        </mvc:view-resolvers>
  1. 处理请求参数
    方法一:只要把方法的参数名称和请求的参数名称对象,springmvc 会将请求参数的值赋值给方法参数,并完成类型转换日期类型需要特殊处理,请求参数类型转换出错,会出现400错误, 日期可以使用 @DateTimeFormat(pattern=“日期格式”)
    @RequestMapping("/m1")
    public String m1(String name, Integer age, @DateTimeFormat(pattern = "yyyy-MM-dd")Date birthday){
        System.out.println("执行了m1方法:"+name+":"+age+":"+birthday);
        return "hello";
    }

方法二:当请求参数较多时,可以把请求参数映射到java对象的属性上

    @RequestMapping("/m2")
    public String m2(User user){
        System.out.println(user);
        return "hello2";
    }
public class User {
    private String name;
    private int age;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthday;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                '}';
    }
}

方法三:把参数信息包含在路径中

    //PathVariable获取一个路径变量的值{id},然后赋值给方法参数
    @RequestMapping("/deleteuser/{id}")
    public String m3(@PathVariable("id") int a){
        System.out.println("参数值:"+a);
        return "hello";
    }
  1. 处理模型数据
    Model接口,需要调用Model 的相关方法把数据存入模型,页面上在再从模型中获取数据并显示;
    model不需要自己创建,只需要在控制器方法上声明一个Model类型的参数,spring会帮我们创建好;跳转至jsp视图之前,springmvc会把model中的每一项数据存入request作用域;model只跟request作用域相关;
    @RequestMapping("/c4")
    public String c4(Model model){
        model.addAttribute("name","zhangsan");
        model.addAttribute("list",Arrays.asList(1,2,3,4));
        return "model";
    }
    @RequestMapping("/c5")
    public ModelAndView c5(){
        ModelAndView mav = new ModelAndView();
        mav.addObject("name","张三");
        mav.addObject("list",Arrays.asList(1,2,3,4));
        mav.setViewName("model");
        return mav;
    }

model.jsp

<html>
<head>
    <title>Title</title>
</head>
<body>
{name}
<ul>
    <c:forEach items="${list}" var="a">
        <li>${a}</li>
    </c:forEach>
</ul>
</body>
</html>

汉字乱码
配置web.xml,CharacterEncodingFilter由spring提供

    <!--配置字符编码过滤器-->
    <filter>
        <filter-name>bb</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>bb</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
@Controller
public class EncodingController {

    @RequestMapping("/b")
    public String encoding(String name){
        System.out.println(name);
        return "encoding";
    }
}
<body>
<form method="post" action="/b">
    用户名:<input type="text" name="name">
    <br>
    <input type="submit" value="提交">
</form>

</body>

使用传统servlet中的类
HttpServletRequest,HttpServletResponse,HttpSession,spring把这些类都创建好了,都可以作为控制器方法的参数,只传入方法就可以了;
El表达式中的变量名会依次查找四个作用域,直到找到为止;如果想直接指定作用域查找如:${sessionScrope.name}只在session中查找如果找不到就不再查找;

异常处理
局部的异常处理器,只针对某一个控制器;

    @ExceptionHandler(Exception.class)  // 异常处理器, 可以指定具体的异常类型
    public String error(Exception e){
        return "error";
    }

全局的异常处理器,针对所有的控制器;

@ControllerAdvice
public class ExcwptionAspect {
    @ExceptionHandler(Exception.class)
    public String exception(Exception e){
        System.out.println("全局异常处理方法");
        return "error";
    }

}

局部得异常处理优先级高于全局的异常处理;

文件上传

  1. pom.xml添加依赖
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.3</version>
        </dependency>
  1. springmvc.xml中对上传文件表单做特殊配置
    <!--配置上传文件表单解析器 id是固定的-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        
    </bean>
  1. 编辑表单页面

enctype规定表单格式

<form action="请求地址" method="post" enctype="multipart/form-data">
	<input type="file" name="请求参数名">
</form>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="image" id="image">
    <input type="submit" value="提交">
</form>

</body>
</html>
@Controller
public class Uploadfile {

    @RequestMapping("/upload")
    public String upload(MultipartFile image) throws IOException {

        System.out.println("上传文件原始名称:"+image.getOriginalFilename());
        System.out.println("上传文件类型:"+image.getContentType());
        System.out.println("上传文件大小:"+image.getSize());

        //上传的文件生成为临时文件,当请求结束时,此临时文件会被删除
        //另存临时文件
        image.transferTo(new File("d:\\"+image.getOriginalFilename()));
        return "hello";
    }
}

图片预览

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="image" id="image" onchange="preview()">
    <input type="submit" value="提交">
</form>
<img src="" id="preview" >
<script>
    function preview() {
        var image = document.getElementById("image");
        var file = image.files[0];

        var reader = new FileReader();
        reader.onload=function () {

            document.getElementById("preview").src=this.result;
        };
        reader.readAsDataURL(file);
    }

</script>
</body>
</html>

对上传文件的限制

从客户端角度限制

<input type="file" name="image" id="image" onchange="preview()" accept=".jpg,.png,.bmp">

服务器端要对上传的文件做检查
图片修改大小 成功
假图片修改大小 报异常

对文件大小做控制

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 限制上传文件的总大小,单位是字节-->
    <property name="maxUploadSize" value="2000"></property>
</bean>

springmvc对静态文件的处理(图片、html、css、js)
springmvc 默认把所有路径都当做了控制器的路径了;

重定向请求

@RequestMapping("test1")
public String test1(){
	//重定向到/test2 控制器
	return "redirect:/test2"
}

spring中的 拦截器

请求到达控制器之前,先经过拦截器,才到达控制器;

Filter过滤器属于web组件,工作于tomcat;
HandlerIntercepter 拦截器属于spring提供的;
拦截器和过滤器的功能相似;

  1. 编写拦截器
package com.westos.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

@Component
public class Interceptor implements HandlerInterceptor {
    
    //在控制器方法执行前被调用,返回true放行请求,返回false则拦截请求
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("======>进入了 interceptor preHandle");
        return true;
    }

    //在控制器方法执行后被调用
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("======>进入了 interceptor postHandler");
    }

    //在控制器和视图都完成后被调用
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("======>进入了 interceptor afterCompletion");
    }
}

  1. 在spring.xml里配置拦截器
    <!--配置上传文件表单解析器 id是固定的-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

    </bean>
        <!--
        /user/* 只能匹配类似于 /user/insert 不能匹配/user/aaa/insert这种
        /user/** 则都可以匹配
        -->

    <!--扫描拦截器-->
    <context:component-scan base-package="com.westos.interceptor"/>
    <!--配置 要拦截那些控制器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/user/*"/>
            <ref bean="interceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

拦截器拦截的顺序,可以通过配置拦截器的顺序来决定;

对json数据的支持

  1. 添加依赖
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.5</version>
        </dependency>
  • @ResponseBody注解,加在控制器方法上,结果就是将控制器方法的返回转换为json字符串,并写入响应;
  • @RestController注解,加在控制器类上,表示所有的控制器方法都加了@ResponseBody注解
@RestController //相当于@Controller 认为每个控制器的方法上都加了 @ResponseBody
public class JsonController {


//    @RequestMapping(path = "/json",method = RequestMethod.GET)
    @GetMapping(path = "/json")
    @ResponseBody //获取控制器方法的返回值,并且把返回值转换为json 字符串,并作为响应体内容返回
    public Student json(){
        Student student = new Student();
        student.setId(1);
        student.setName("王小帅");
        return student;
    }

}
  • 其他注解
    @RequestMapping 映射路径,不区别get,post

RequestMapping细分:
@GetMapping 专门匹配 get请求 一般对应查询操作
@PostMapping 匹配post请求 一般对应新增操作
@DeleteMapping 匹配delete请求 对应删除操作
@PutMapping 匹配put请求 对应修改操作

  • RequestBody
    把请求中的json字符串,转换成java对象
    @PostMapping(path = "/json")
    @ResponseBody //获取控制器方法的返回值,并且把返回值转换为json 字符串,并作为响应体内容返回
    public Student json(){
        Student student = new Student();
        student.setId(1);
        student.setName("王小帅");
        return student;
    }

    @PostMapping("/json3")
    //@RequestBody作用是吧请求体中的json字符串,转换为java中的对象
    public void json3(@RequestBody Student student){
        System.out.println(student);
    }
<body>
<input type="button" value="获取学生数据" onclick="getStudent()">
<input type="button" value="发送学生数据" onclick="sendStudent()">
<script>
    function getStudent() {
        var xhr = new XMLHttpRequest();
        xhr.onload=function () {
            var student = JSON.parse(xhr.responseText);
            console.log(student);
        };
        xhr.open("post","/json1",true)
        xhr.send();
    }

    function sendStudent() {
        var student={"id":2,"name":"李四"};
        var xhr = new XMLHttpRequest();
        xhr.open("post","/json3",true);
        xhr.setRequestHeader("content-type","application/json");
        //将js对象 转为json字符串 并作为请求体发送给服务器
        xhr.send(JSON.stringify(student));
    }

</script>
</body>

ajax 请求跨域

cors 技术名称,用来授权给不同的机器来访问我的资源;
ip不一样或端口号不一样都认为是不同的域,称之为跨域;

案例:
localhost:8080 提供控制器,返回json数据
localhost:9090 ajax 获取 8080上的json数据,默认情况下没有权限访问;
需要在8080上通过一种cors的技术允许其他域的机器访问我的数据

提供了@CrossOrigin("允许访问我的数据的ip地址")注解加在方法上,表示只有这个方法允许跨域;也可以加在控制器类上,表示这个类的所有方法都允许跨域;仅仅针对于ajax;

上一篇: 小程序接口对接

下一篇: Spring MVC