Spring MVC 学习笔记

入门程序编写步骤

  1. 创建maven项目,选择webapp,让maven帮我们创建目录
  2. 在pom.xml中导入依赖
  3. 配置web.xml
	 <!--配置前端控制器-->
	 <servlet>
	   <servlet-name>dispatcherServlet</servlet-name>
	   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	   <init-param>
	     <!--配置DispatcherServlet的参数,让其可以加载springmvc.xml-->
	     <param-name>contextConfigLocation</param-name>
	     <param-value>classpath:springmvc.xml</param-value>
	   </init-param>
	   <!--使该servlet在服务器创建时创建-->
	   <load-on-startup>1</load-on-startup>
	 </servlet>
	 <servlet-mapping>
	   <servlet-name>dispatcherServlet</servlet-name>
	   <url-pattern>/</url-pattern>
	 </servlet-mapping>
	  
	<!--配置解决中文乱码的过滤器-->
	<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>
  1. 配置springmvc.xml
	<!-- 开启注解扫描 -->
	<context:component-scan base-package="cn.itcast"/>
	
	<!-- 视图解析器对象 -->
	<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<!-- 调用添加了RequestMapping的注解的方法后会跳转到prefix对应的目录下的该方法的返回值的suffix对应的后缀里 -->
	    <property name="prefix" value="/WEB-INF/pages/"/>
	    <property name="suffix" value=".jsp"/>
	</bean>
	
	<!-- 开启SpringMVC框架注解的支持 -->
	<mvc:annotation-driven/>
  1. 编写控制器类
    访问/user/hello路径时就会调用sayHello方法,并且会跳转到/WEB-INF/pages/success.jsp页面中
// 控制器类
@Controller
@RequestMapping(path="/user")
public class HelloController {

    /**
     * 入门案例
     * @return
     */
    @RequestMapping(path="/hello")
    public String sayHello(){
        System.out.println("Hello StringMVC");
        return "success";
    }
}

  1. 执行流程
    在这里插入图片描述
    在这里插入图片描述

使用重定向而不是转发跳转

在控制器的方法中返回 redirect:+路径
例如:

return "redirect:/index.jsp";

配置不拦截指定资源

在web.xml中配置,与顺序无关

  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
  </servlet-mapping>

RequestMapping 注解

作用:
	用于建立请求 URL 和处理请求方法之间的对应关系。
出现位置:
	类上:
		请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。
		它出现的目的是为了使我们的 URL 可以按照模块化管理:
		例如:
			账户模块:
				/account/add
				/account/update
				/account/delete
			...
			订单模块:
				/order/add
				/order/update
				/order/delete
		/account和/order就是把 RequsetMappding 写在类上,使我们的 URL 更加精细。
	方法上:
		请求 URL 的第二级访问目录。
属性:
	value:用于指定请求的 URL。它和 path 属性的作用是一样的。
	method:用于指定请求的方式。
	params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和配置的一模一样。
		例如:
			params = {"accountName"},表示请求参数必须有 accountName
			params = {"moeny!100"},表示请求参数中 money 不能是 100。
	headers:用于指定限制请求消息头的条件。
注意:
	以上四个属性只要出现 2 个或以上时,他们的关系是与的关系

请求参数绑定机制

浏览器请求方法时,如果提交的参数的键和方法的参数名相同,Spring MVC会自动为方法参数复制

支持基本类型和字符串的封装

如果要封装对象,方法参数是对象类,请求参数是该类的属性名

如果要封装的对象的属性不是基本数据类型,请求的参数的键可以用属性名.属性名

如果要封装list和map,请求的参数的键的写法是
	list[0].属性名
	map['key'].属性名

自定义类型转换器

需要实现org.springframework.core.convert.converter.Converter<S,T>接口

/**
 * 把字符串转换日期
 */
public class StringToDateConverter implements Converter<String,Date>{

    /**
     * String source    传入进来字符串
     * @param source
     * @return
     */
    public Date convert(String source) {
        // 判断
        if(source == null){
            throw new RuntimeException("请您传入数据");
        }
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");

        try {
            // 把字符串转换日期
            return df.parse(source);
        } catch (Exception e) {
            throw new RuntimeException("数据类型转换出现错误");
        }
    }

}

在springmvc.xml中配置自定义类型转换器

	<!--配置自定义类型转换器-->
	<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
	    <property name="converters">
	        <set>
	        	<!-- -->
	            <bean class="cn.itcast.utils.StringToDateConverter"/>
	        </set>
	    </property>
	</bean>
	<!---->
	<mvc:annotation-driven conversion-service="conversionService"/>

在控制器的方法中获取原生servletAPI

在方法参数里加上HttpServletRequest request, HttpServletResponse response就可以了

RequestParam注解

当控制器中方法参数名和请求key不一致时可以用该注解将指定的请求key封装到方法参数中

作用:
	把请求中指定名称的参数给控制器中的形参赋值。
属性:
	value:请求参数中的名称。
	required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。

RequestBody注解

把post请求的请求体赋值给方法参数,异步时使用

作用:
	用于获取请求体内容。直接使用得到是 key=value&key=value...结构的数据。get 请求方式不适用。
属性:
	required:是否必须有请求体。默认值是:true。当取值为 true,get 请求方式会报错。如果取值为 false,get 请求得到是 null。

PathVaribale注解

用来把请求的路径赋值给方法参数

作用:
	用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。
	url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。
属性:
	value:用于指定 url 中占位符名称。
	required:是否必须提供占位符。

@RequestMapping("/usePathVariable/{id}")
public String usePathVariable(@PathVariable("id") Integer id){
System.out.println(id);
return "success";
}

REST 风格

控制器中多个方法的路径一样,用请求方式来区分到底执行哪个方法

RequestHeader注解

作用:
	用于获取请求消息头。
属性:
	value:提供消息头名称
	required:是否必须有此消息头
注:
	在实际开发中一般不怎么用。

CookieValue注解

作用:
	用于把指定 cookie 名称的值传入控制器方法参数。
属性:
	value:指定 cookie 的名称。
	required:是否必须有此 cookie。

ModelAttribute注解

作用:
	该注解是 SpringMVC4.3 版本以后新加入的。它可以用于修饰方法和参数。
	出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可
	以修饰有具体返回值的方法。
	出现在参数上,获取指定的数据给参数赋值。
属性:
	value:用于获取数据的 key。key 可以是 POJO 的属性名称,也可以是 map 结构的 key。
应用场景:
	当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
	例如:
		我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数
		据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。

  1. ModelAttribute修饰的方法会先于RequestMapping修饰的方法执行,并且也可以接受请求参数,有点类似执行一次的过滤器
@ModelAttribute
public void showModel(User user) {
System.out.println("执行了 showModel 方法"+user.getUsername());
return user;
}

@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user) {
System.out.println("执行了控制器的方法"+user.getUsername());
return "success";
}
  1. testModelAttribute方法可以获取showModel方法参数Map集合里的对象
@ModelAttribute
public void showModel(String username,Map<String,User> map) {
//模拟去数据库查询
User user = findUserByName(username);
System.out.println("执行了 showModel 方法"+user);
map.put("abc",user);
}
/**
* 模拟修改用户方法
* @param user
* @return
*/
@RequestMapping("/updateUser")
public String testModelAttribute(@ModelAttribute("abc")User user) {
System.out.println("控制器中处理请求的方法:修改用户:"+user);
return "success";
}

SessionAttribute注解

作用:
	用于多次执行控制器方法间的参数共享。
属性:
	value:用于指定存入的属性名称
	type:用于指定存入的数据类型。

Model类

在控制器的方法的参数里加上Model这个参数,在Model里存的值会被框架存到session域中

    @RequestMapping(value="/testSessionAttributes")
    public String testSessionAttributes(Model model){
        System.out.println("testSessionAttributes...");
        // 底层会存储到request域对象中
        model.addAttribute("msg","美美");
        return "success";
    }

控制器中方法的返回值

如果有返回值,会跳转到对应的jsp里,没有返回值的会默认跳转到RequestMapping注解对应的jsp文件里

设置前端控制器不拦截哪些资源

在springmvc.xml中添加

	<!--js是指定不拦截的目录-->
    <mvc:resources location="/js/" mapping="/js/**"/>

异步发送接收json数据

$.ajax({
                    // 编写json格式,设置属性和值
                    url:"user/testAjax",
                    contentType:"application/json;charset=UTF-8",
                    data:'{"username":"hehe","password":"123","age":30}',
                    dataType:"json",
                    type:"post",
                    success:function(data){
                        // data服务器端响应的json的数据,进行解析
                        alert(data);
                        alert(data.username);
                        alert(data.password);
                        alert(data.age);
                    }
                });

需要导入jackson的jar包,Spring MVC会自动的把RequestBody 的json数据封装到User 对象里,返回时因为ajax请求里要求响应的数据是json数据(dataType:“json”,),所以也会把ResponseBody 修饰的对象转成json格式响应

    @RequestMapping("/testAjax")
    public @ResponseBody User testAjax(@RequestBody User user){
        System.out.println("testAjax方法执行了...");
        // 客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中
        System.out.println(user);
        // 做响应,模拟查询数据库
        user.setUsername("haha");
        user.setAge(40);
        // 做响应
        return user;
    }

文件上传

在这里插入图片描述
springmvc.xml配置文件

    <!--配置文件解析器对象-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760" />
    </bean>

jsp文件

<h3>Springmvc文件上传</h3>

    <form action="/user/fileupload2" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload" /><br/>
        <input type="submit" value="上传" />
    </form>

控制器方法

    @RequestMapping("/fileupload2")
    //MultipartFile 的对象名要和jsp表单中的name一样
    public String fileuoload2(HttpServletRequest request, MultipartFile upload) throws Exception {
        System.out.println("springmvc文件上传...");

        // 使用fileupload组件完成文件上传
        // 上传的位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        // 判断,该路径是否存在
        File file = new File(path);
        if(!file.exists()){
            // 创建该文件夹
            file.mkdirs();
        }

        // 说明上传文件项
        // 获取上传文件的名称
        String filename = upload.getOriginalFilename();
        // 把文件的名称设置唯一值,uuid
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid+"_"+filename;
        // 完成文件上传
        upload.transferTo(new File(path,filename));

        return "success";
    }

跨服务器文件上传

path这个路径是另一个服务器的servlet

    @RequestMapping("/fileupload3")
    public String fileuoload3(MultipartFile upload) throws Exception {
        System.out.println("跨服务器文件上传...");

        // 定义上传文件服务器路径
        String path = "http://localhost:9090/uploads/";

        // 说明上传文件项
        // 获取上传文件的名称
        String filename = upload.getOriginalFilename();
        // 把文件的名称设置唯一值,uuid
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid+"_"+filename;

        // 创建客户端的对象
        Client client = Client.create();

        // 和图片服务器进行连接
        WebResource webResource = client.resource(path + filename);

        // 上传文件
        webResource.put(upload.getBytes());

        return "success";
    }

异常处理

在这里插入图片描述自定义异常类可以不需要
异常处理类

public class SysExceptionResolver implements HandlerExceptionResolver{

    /**
     * 处理异常业务逻辑
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @return
     */
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        mv.addObject("errorMsg",e.getMessage());
        mv.setViewName("error");
        return mv;
    }

}

springmvc.xml

    <!--配置异常处理器-->
    <bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"/>

拦截器

Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,
用于对处理器进行预处理和后处理。
用户可以自己定义一些拦截器来实现特定的功能。

谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。
拦截器链就是将拦截器按一定的顺序联结成一条链。
在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?
是的它和过滤器是有几分相似,但是也有区别,接下来我们就来说说他们的区别:
	过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。
	拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。
	过滤器在 url-pattern 中配置了/ *之后,可以对所有要访问的资源拦截。
	拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦截的。
	它也是 AOP 思想的具体应用。
	
我们要想自定义拦截器, 要求必须实现:HandlerInterceptor 接口。

springmvc.xml

<!--配置拦截器-->
    <mvc:interceptors>
        <!--配置拦截器-->
        <mvc:interceptor>
            <!--要拦截的具体的方法-->
            <mvc:mapping path="/user/*"/>
            <!--不要拦截的方法
            <mvc:exclude-mapping path=""/>
            -->
            <!--配置拦截器对象-->
            <bean class="cn.itcast.controller.cn.itcast.interceptor.MyInterceptor1" />
        </mvc:interceptor>

        <!--配置第二个拦截器-->
        <mvc:interceptor>
            <!--要拦截的具体的方法-->
            <mvc:mapping path="/**"/>
            <!--不要拦截的方法
            <mvc:exclude-mapping path=""/>
            -->
            <!--配置拦截器对象-->
            <bean class="cn.itcast.controller.cn.itcast.interceptor.MyInterceptor2" />
        </mvc:interceptor>
    </mvc:interceptors>

拦截器类

/**
 * 自定义拦截器
 */
public class MyInterceptor1 implements HandlerInterceptor{

    /**
     * 预处理,controller方法执行前
     * return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
     * return false不放行
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor1执行了...前1111");
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
        return true;
    }

    /**
     * 后处理方法,controller方法执行后,success.jsp执行之前
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor1执行了...后1111");
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
    }

    /**
     * success.jsp页面执行后,该方法会执行
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor1执行了...最后1111");
    }

}
©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页