Spring集成Web开发

ContextLoaderListener监听器

应用上下文对象是通过new ClasspathXmlApplicationContext(spring配置文件)方式获取的,但是每次从
容器中获得Bean时都要编写new ClasspathXmlApplicationContext(spring配置文件) ,这样的弊端是配置
文件加载多次,应用上下文对象创建多次。
在Web项目中,可以使用ServletContextListener监听Web应用的启动, 我们可以在Web应用启动时,就加
载Spring的配置文件,创建应用上下文对象ApplicationContext,在将其存储到最大的域servletContext域
中,这样就可以在任意位置从域中获得应用上下文ApplicationContex对象了。

自定义监听器实现

业务层代码

package com.ytl.web;


import com.ytl.listen.WebApplicationContextUtils;
import com.ytl.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
//        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//        ApplicationContext applicationContext = (ApplicationContext) this.getServletContext().getAttribute("applicationContext");
        ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.save();
        ((ClassPathXmlApplicationContext) applicationContext).close();
    }
}

工具类

package com.ytl.listen;

import org.springframework.context.ApplicationContext;

import javax.servlet.ServletContext;

public class WebApplicationContextUtils {
    public static ApplicationContext getWebApplicationContext(ServletContext servletContext){
        return (ApplicationContext) servletContext.getAttribute("applicationContext");
    }
}

监听器类

package com.ytl.listen;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class ContextLoaderListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        ServletContext servletContext = servletContextEvent.getServletContext();
        //读取 web.xml 中的全局参数
        String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(contextConfigLocation);

        //将创建的配置文件对象存入web中的最大的 ServletContext 域
        servletContext.setAttribute("applicationContext", applicationContext);
        System.out.println("上下文对象创建完毕");

    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        ((ClassPathXmlApplicationContext)servletContextEvent.getServletContext().getAttribute("applicationContext")).close();
        System.out.println("上下文对象销毁完毕");
    }
}

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
<!--  全局初始化参数-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:applicationContext.xml</param-value>
  </context-param>
<!--  配置servlet-->
  <servlet>
    <servlet-name>userServlet</servlet-name>
    <servlet-class>com.ytl.web.UserServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>userServlet</servlet-name>
    <url-pattern>/userServlet</url-pattern>
  </servlet-mapping>
<!--  配置自定义监听器-->
  <listener>
<!--    <listener-class>com.ytl.listen.ContextLoaderListener</listener-class>-->
<!--    spring提供的-->
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>


Spring提供的获取应用上下文的工具

  1. 配置ContextLoaderListener监听器
  2. 使用WebApplicationContextUtils获得应用上下文
        ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        assert applicationContext != null;
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.save();

SpringMVC

开发步骤

客户端发起请求,服务器接收请求,执行逻辑并进行视图跳转。

在这里插入图片描述

  1. 导入SpringMVC相关坐标
  2. 配置SpringMVC核心控制器DispathcerServlet
  3. 创建Controller类和视图页面
  4. 使用注解配置Controller类中业务方法的映射地址
  5. 配置SpringMVC核心文件spring-mvc.xml
  6. 客户端发起请求测试

web.xml

<!--  配置springMvc的前端控制器-->
    <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*:spring-mvc.xml</param-value>
        </init-param>
        <!--  web服务器启动时就加载此Servlet-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <!--    所有请求都经过该控制器-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <!--  全局初始化参数-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:applicationContext.xml</param-value>
    </context-param>

spring-mvc.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">


<!--    Controller的组件扫描-->
<!--    spring-mvc只负责扫描前端控制器-->
    <context:component-scan base-package="com.ytl.controller" />


</beans>

UserController

package com.ytl.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

//将此类放在spring容器中
@Controller
public class UserController {
    @RequestMapping("/login")
    public String save() {
        System.out.println("前端控制器启动了");
        return "success.jsp";
    }

}

SpringMvc的执行流程

  1. 用户发送请求至前端控制器 DispatcherServlet
  2. DispatcherServlet 收到请求调用HandlerMapping处理器映射器
  3. 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
  4. DispatcherServlet调用HandlerAdapter处理器适配器。
  5. HandlerAdapter 经过适配调用具体的处理器(Controller,也叫后端控制器)。
  6. Controller 执行完成返回ModelAndView
  7. HandlerAdaptercontroller执行结果ModelAndView返回给DispatcherServlet.
  8. DispatcherServletModelAndView传给ViewReslover视图解析
  9. ViewReslover解 析后返回具体View。
  10. DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
  11. DispatcherServlet 响应用户。
    在这里插入图片描述

SpringMVC注解解析

名称说明
@RequestMapping用于建立请求URL和处理方法之间的对应关系
@ResponseBody告知Spring容器不进行试图跳转,直接进行数据响应

作用:用于建立请求URL和处理请求方法之间的对应关系位置
405- Method not Allowed

可以放的位置

  • 类上,请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录
  • 方法上,请求URL的第二级访问目录,与类上的使用 @ReqquestMapping 标注的一级目录一起组成访问虚拟路径
//默认从当前二级目录中寻找
return "success.jsp";
//默认从根路径下寻找
return "/success.jsp";

属性:value,method,params

  • value:用于指定请求的URL。它和path属性的作用是一样的
  • method:用于指定请求的方式,可取值有:
    • RequestMethod.POST
    • RequestMethod.GET
  • params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样例如:
  • params = {“username”,“age!18”}
  • 表示请求参数中必须有username,age,且age的值不能为18
    <!--    Controller的组件扫描-->
    <!--    spring-mvc只负责扫描前端控制器-->
<!--    <context:component-scan base-package="com.ytl.controller"/>-->
    <context:component-scan base-package="com.ytl">
<!--        会扫描当前包下的Controller注解-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <!--        不会扫描当前包下的Service注解-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>

SpringMVC的数据响应

  1. 页面跳转
    1. 直接返回字符串
    2. 通过ModelAndView对象返回
  2. 回写数据
    1. 直接返回字符串
    2. 返回对象或集合

页面跳转

  1. 请求转发(默认的)
<!--    配置内部资源视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--        配置前缀,好像无法使用重定向?-->
        
        <property name="prefix" value="/jsp/" />
<!--        配置后缀-->
        <property name="suffix" value=".jsp" />
    </bean>
return "success";//相当于
return "forward:/jsp/success.jsp"
  1. 重定向
return "redirect:/jsp/success.jsp"
返回ModelAndView对象
    @RequestMapping("/login2")
    public ModelAndView login2(){
        System.out.println("来到登录功能2");
        /*
        Model:模型,用来封装数据
        View:视图,返回数据
         */

        ModelAndView modelAndView = new ModelAndView();
        //设置视图名称
        modelAndView.setViewName("success");
        //设置模型数据
        modelAndView.addObject("userName", "余腾龙");
        return modelAndView;
    }

	@RequestMapping("/login3")
    public ModelAndView login3(ModelAndView modelAndView){
        System.out.println("来到登录功能3");
        //设置视图名称
        modelAndView.setViewName("success");
        //设置模型数据
        modelAndView.addObject("userName", "余腾龙2");
        return modelAndView;
    }

    @RequestMapping("/login4")
    public String login4(Model model){
        //将模型和数据拆开
        System.out.println("来到登录功能4");
        //设置模型数据
        model.addAttribute("userName", "余腾龙2");
        return "success";
    }
注意:
maven项目web.xml版本用的是2.3版本的,如果web.xml是2.3版本的话,jsp里面有个默认的属性是:

<%@ page isELIgnored="true"%>
如果这个属性设置为true的话,默认el表达式是关闭的,所以我们可以在.jsp文件里面加入如下代码:

<%@ page isELIgnored="false"%>
如果是一两个jsp文件,我们这样改可能没什么,如果是太多jsp文件的话,这样子改就未必太麻烦了,如果我们想用一劳永逸的方法的话,最好是去修改xml的版本问题:

我们可以把web.xml的版本换成3.0的,这样子是默认支持el表达式的,我们就不需要再去修改jsp文件了。
返回字符串形式

此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转

    @RequestMapping("/login")
    public String login(){
        System.out.println("来到登录功能");
        //默认省略forward请求转发
//        return "forward:/success.jsp";
        return "redirect:/success";
    }

回写数据

直接返回字符串

web:responsse.getWriter().print(“hello World!”)


    @RequestMapping("/welcome1")
    public void welcome1(HttpServletResponse response) throws IOException {
        //加上形参,Spring容器就会帮忙注入
        //web的回写方法
        System.out.println("来到欢迎功能1");
        response.getWriter().println("welcome1");
    }
    
    @ResponseBody//告知Spring 此方法是直接返回字符串
    @RequestMapping("/welcome2")
    public String welcome2() throws IOException {
        //加上形参,Spring容器就会帮忙注入
        //web.的回写方法
        System.out.println("来到欢迎功能2");
        return "welcome2";
    }
    @ResponseBody//告知Spring 此方法是直接返回字符串
    @RequestMapping("/welcome3")
    public String welcome3() throws IOException {
        User user = new User("liSi", 30);
        //JSON转换工具将对象转换为JSON格式的字符串
        System.out.println("来到欢迎功能3");
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(user);
        return json;
    }


返回对象或集合
	@ResponseBody//告知Spring 此方法是直接返回字符串
    @RequestMapping("/welcome4")
    public User welcome4() {
        System.out.println("来到欢迎功能4");
        //期望Spring自动的将User对象转换为JSON格式的字符串
        //直接返回即可,需要在spring-mvc.xml文件中配置
        return new User("liSi", 30);
    }

spring-mvc.xml

    <!--    json转换的配置-->
    <!--    配置处理器映射器,转JSON字符串用的-->
    <bean id="requestMappingHandlerAdapter"
          class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
            </list>
        </property>
    </bean>
    <!--    配置处理器映射器,注解方式的mvc的注解驱动-->
    <mvc:annotation-driven />
    <!--    json转换的配置-->
	在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。
	使用<mvc:annotation- driven>自动加载RequestMappingHandlerMapping (处理映射器)和
	RequestMappingHandlerAdapter (处理适配器), 可用在Spring-xml.xml配置文件中使用
	<mvc:annotation- driven>替代注解处理器和适配器的配置。
	同时使用<mvc:annotation-driven>默认底层就会集成jackson进行对象或集合的ison格式字符串的转换。

pom.xml

<!--    JSON-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.0</version>
    </dependency>
    <!--    JSON-->

SpringMVC获取请求数据

SpringMVC可以接收如下类型的数据:

  1. 基本类型参数
  2. POJO类型参数,简单JavaBean
  3. 数组类型参数
  4. 集合类型参数

获得基本类型参数

Controller中的业务方法的参数名称要与请求参数的name一致,参数值就会自动映射匹配

	@ResponseBody//此处方法代表不进行页面跳转
    @RequestMapping("/save1")
    public void save1(String userName, int age){
        //形参要与传入的参数名字保持一致
        System.out.println("Controller中的save1方法执行");
        System.out.println("接收到的数据:userName=="+userName+"\tage=="+age);
    }

POJO类型参数,简单JavaBean

Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数值就会自动映射匹配

    @ResponseBody//此处方法代表不进行页面跳转
    @RequestMapping("/save2")
    public void save2(User user){
        //形参要与传入的参数名字保持一致name,age
        System.out.println("Controller中的save2方法执行");
        System.out.println("接收到的数据:"+user);
    }

数组类型参数

Controller中的业务方法的数组名称与请求参数的name一致,参数值就会自动映射匹配

/save3?strs=zhangsan&strs=lisi&strs=wangwu

    @ResponseBody//此处方法代表不进行页面跳转
    @RequestMapping("/save3")
    public void save3(String[] strs){
        //形参数组要与传入的数组参数名字保持一致,且传入的数据类型要一致
        System.out.println("Controller中的save3方法执行");
        System.out.println("接收到的数据:"+ Arrays.toString(strs));
    }

集合类型参数

POJO包装获取集合

获取集合参数时,要将集合参数包装到一个POJO当中才可以
VO对象用泛型就会抛出索引越界异常

VO

此处用泛型会抛出索引越界异常

package com.ytl.domain;

import java.util.List;

/**
 * Value Object 数据对象
 * View Object 视图对象
 * 这里用来测试集合数据的接收
 */
public class VO {
    private List<User> list;

    @Override
    public String toString() {
        return "VO{" +
                "list=" + list +
                '}';
    }

    public List<User> getList() {
        return list;
    }

    public void setList(List<User> list) {
        this.list = list;
    }
}

UserController

    @ResponseBody//此处方法代表不进行页面跳转
    @RequestMapping("/save4")
    public void save4(VO userVo){
        //形参数组要与传入的数组参数名字保持一致,且传入的数据类型要一致
        System.out.println("Controller中的save4方法执行");
        System.out.println("接收到的数据:"+ userVo);
    }
<form action="${pageContext.request.contextPath}/user/save4" method="post">
<%--    表明是第几个User对象的name age--%>
    <p>第一个user对象</p>
    <input type="text" name="list[0].name" /><br />
    <input type="text" name="list[0].age" /><br />
    <p>第二个user对象</p>
    <input type="text" name="list[1].name" /><br />
    <input type="text" name="list[1].age" /><br />
    <input type="submit" value="提交">
</form>
Ajax获取集合

当使用Ajax提交时,可以指定 contentType为json形式,
那么在方法参数位置使用@RequestBody
可以直接接收集合数据而无需使用POJO进行包装

UserController

    @ResponseBody//此处方法代表不进行页面跳转
    @RequestMapping("/save5")
    public void save5(@RequestBody List<User> userList){
        System.out.println("Controller中的save5方法执行");
        System.out.println("接收到的数据:"+ userList);
    }

ajax·jsp


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>ajax测试</title>
    <script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.11.3.min.js"></script>
</head>
<body>
<script>
    var userList = new Array();
    userList.push({name:"张三",age:18});
    userList.push({name:"李四",age:36});
    userList.push({name:"王五",age:72});
    $.ajax({
        type: "POST",
        url:"${pageContext.request.contextPath}/user/save5",
        data:JSON.stringify(userList),
        contentType:"application/json;charset=utf-8"
    })
</script>
</body>
</html>

此处Web的版本如果是2.x的话,${ } 会被编译成 $%7B %7D
解决方法:
将web的版本改为4.0

<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">
</web-app>

静态资源的开启访问

自己配置访问模式
<!--    在Spring框架当中,开放资源的访问权限-->
    <mvc:resources mapping="/js/**" location="/js/" />
    <mvc:resources mapping="/img/**" location="/img/" />
mapping:映射地址,在服务端找资源时的地址 
location:实际地址,资源实际所在的路径
需要开启其他,就再加一个

spring默认配置

    <mvc:default-servlet-handler />
代表spring无法找到静态资源时,会将该工作交给原始容器去找(如:Tomcat)

请求数据乱码问题

配置全局乱码过滤器

web.xml

    <!--  配置全局过滤的filter-->
    <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>
    <!--  配置全局过滤的filter-->

参数绑定注解@RequestParam

用于请求参数名称与Controller里的业务方法参数名称不统一时,可以用此注解显示的绑定

/save6?name=zhangsan

    @ResponseBody//此处方法代表不进行页面跳转
    @RequestMapping("/save6")
    public void save6(@RequestParam(value="name") String userName) {
        //形参要与传入的参数名字不一致时要用@RequestParam
        System.out.println("Controller中的save6方法执行");
        System.out.println("接收到的数据:userName=="+userName);
    }
  1. value:请求参数名称,只有一个参数,该参数名可以省略
  2. required:此在指定请求参数是否必须包含,默认为true,提交时没有此参数会报错
  3. defaultValue:当没有此参数时 ,使用指定的默认值赋值

获取Restful风格的参数

Restful是一种软件架构风格设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等
Restful风格的请求是使用 ”url+请求方式“ 表示一次请求目的的,HTTP协议里面四个表示操作方式的动词如下:

  • GET:用于获取资源
  • POST:用于新建资源
  • PUT:用于更新资源
  • DELETE:用于删除资源

例如:

  • /user/1 GET:得到id=1的user
  • /user/1 DELETE:删除id=1的user
  • /user/1 PUT:更新id=1的user
  • /user POST:新增user

/quick1/zhangsan

    @ResponseBody//此处方法代表不进行页面跳转
    @RequestMapping(value = "/quick1/{name}",method = RequestMethod.GET)
    public void quick1(@PathVariable(value="name") String userName) {
        //形参要与传入的参数名字不一致时要用@RequestParam
        System.out.println("Controller中的quick1方法执行");
        System.out.println("接收到的数据:userName=="+userName);
    }

@RequestMapping("/quick1/{name}") 里面的name必须与@PathVariable里的value值统一
@RequestMapping里的method属性来配合区分请求方式

类型转换器

SpringMVC已经默认提供了一些常用的类型转换器

  1. 定义转换器类实现Converter接口
  2. 在配置文件中声明转换器
  3. annotation-driven中引用转换器

例如:yyyy-MM-dd格式的日期型字符串转换为Date类型

    @ResponseBody//此处方法代表不进行页面跳转
    @RequestMapping(value = "/quick2/{date}",method = RequestMethod.GET)
    public void quick2(@PathVariable(value="date") Date date) {
        System.out.println("Controller中的quick2方法执行");
        System.out.println("接收到的数据:date=="+date);
    }

自定义的转换器DateConverter

package com.ytl.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 simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date parseDate = null;
        try {
            parseDate = simpleDateFormat.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return parseDate;
    }
}

引用转换器

	<mvc:annotation-driven conversion-service="conversionService" />
<!--    声明转换器-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="com.ytl.converter.DateConverter" />
            </list>
        </property>
    </bean>

获得Servlet相关API

SpringMVC支持使用原始的ServletAPI对象作为控制器方法的参数进行注入,常用的对象如下:

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession

想要什么对象,就在方法中写其的形参,Spring会自动注入

    @ResponseBody//此处方法代表不进行页面跳转
    @RequestMapping(value = "/quick3/")
    public void quick3(HttpServletRequest request, HttpServletResponse response, 
    HttpSession session) {
        System.out.println(request);
        System.out.println(response);
        System.out.println(session);
    }

获取请求头

@RequestHeader

使用它可以获得请求头信息,相当于web阶段的reqeust.getheader(name)
属性如下:

  • value:请求头的名称
  • required:是否必须携带此请求头
@CookieValue

使用它可以获得指定Cookie的值
属性如下:

  • value:指定cookie的名称
  • required:是否必须携带此cookie
    @ResponseBody//此处方法代表不进行页面跳转
    @RequestMapping(value = "/quick4/")
    public void quick4(@RequestHeader(value = "User-Agent") String userAgent,
                       @CookieValue("JSESSIONID") String jSessionId) {
        System.out.println("Controller中的quick4方法执行");
        System.out.println("请求头的User-Agent:"+userAgent);
        System.out.println("cookie中的:JSESSIONID:"+jSessionId);
    }

文件上传

文件上传客户端三要素

  1. 表单项type="file"
  2. 表单的提交方式是post
  3. 表单的enctype属性是多部分表单形式,及enctype="multipart/form-data"

文件上传原理

  • 当form表单修改为多部分表单时,request.getParameter()将失效
  • 当form表单的enctype="application/x-www-form-urlencoded"时,form表单正文内容格式是:key=value&key=value,默认就是此方式
  • 当form表单的enctype="mutilpart/form-data"时,请求正文内容就变成多部份形式了
    在这里插入图片描述

单文件上传步骤

1. 导入fileuploadio坐标
<!--        文件上传-->
        <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.3</version>
        </dependency>
<!--        文件上传-->
2. 配置文件解析器
<!--    文件上传-->
    <bean id="commonsMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--        上传文件总大小-->
        <property name="maxUploadSize" value="5242800" />
        <!--        上传单个文件的大小-->
        <property name="maxUploadSizePerFile" value="5242800" />
<!--        上传文件的编码类型-->
        <property name="defaultEncoding" value="UTF-8" />
    </bean>
<!--    文件上传-->
3. 编写单文件上传代码
    @ResponseBody//此处方法代表不进行页面跳转
    @RequestMapping(value = "/uploadFile1", method = RequestMethod.POST)
    public void uploadFile1(String name, MultipartFile uploadFile)
     throws IOException {
        //单个文件上传
        System.out.println("Controller中的uploadFile1方法执行");
        System.out.println("name=="+name);
        System.out.println("uploadFile=="+uploadFile);
        //获取表单上传项里的name属性
        String name1 = uploadFile.getName();
        //获取文件名称
        String originalFilename = uploadFile.getOriginalFilename();
        //文件流实例化,参数是一个File对象
        uploadFile.transferTo(new File("upload\\"+originalFilename));
        System.out.println("name1==="+name1+"\tfileName===="+originalFilename);
    }
3. 1编写多文件上传代码
    @ResponseBody//此处方法代表不进行页面跳转
    @RequestMapping(value = "/uploadFile2", method = RequestMethod.POST)
    public void uploadFile2(String name, MultipartFile[] uploadFiles)
     throws IOException {
        //多个文件上传
        System.out.println("Controller中的uploadFile2方法执行");
        System.out.println("name=="+name);
        for(MultipartFile uploadFile: uploadFiles){
            //获取表单上传项里的name属性
            String name1 = uploadFile.getName();
            //获取文件名称
            String originalFilename = uploadFile.getOriginalFilename();
            //文件流实例化,参数是一个File对象
            uploadFile.transferTo(new File("upload\\"+originalFilename));
            System.out.println("name1==="+name1+"\tfileName===="+originalFilename);
        }
    }
    @ResponseBody//此处方法代表不进行页面跳转
    @RequestMapping(value = "/uploadFile2", method = RequestMethod.POST)
    public void uploadFile2(String name, MultipartFile uploadFile1,MultipartFile uploadFile2) 
    throws IOException {
        //也可以使用该方法
    }

JdbcTemplate

开发步骤

  1. 导入spring-jdbcspring-tx坐标
  2. 创建数据库和实体
  3. 创建jdbc-Template
  4. 执行数据库操作
    <!--        数据库操作-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.0.5.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.0.5.RELEASE</version>
    </dependency>
    <!--        数据库操作-->
 @Test
    //调试JdbcTemplate开发步骤
    public void test1() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/cartoontest");
        dataSource.setUser("root");
        dataSource.setPassword("123456");
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //设置数据源对象,知道数据库在哪
        jdbcTemplate.setDataSource(dataSource);
        //执行操作,update添加,删除,修改;query:用于查询
        int rows = jdbcTemplate.update("insert into admin values(3, ?, ?,?)",
                "admin3", "123456", "汤姆");
        System.out.println(rows);
//        jdbcTemplate.query("select * from admin",);
    }

spring产生JdbcTemplate对象

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       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">
    <!--    加载外部的properties文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 此处name是当前类set方法去掉set字且首字母小写的结果-->
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
<!--    配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>

JdbcTemplateCRUDTest.java

package com.ytl.test;

import com.ytl.domain.Admin;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)//利用导入的包进行测试
@ContextConfiguration("classpath:applicationContext.xml")//导入测试所用的配置文件
public class JdbcTemplateCRUDTest {
    @Autowired//自动在spring容器寻找类型为JdbcTemplate的变量
    private JdbcTemplate jdbcTemplate;

    @Test
    public void testUpdate(){
        int rows = jdbcTemplate.update("update admin set trueName = ? where id = ?", "杰克", 4);
        System.out.println(rows);
        rows = jdbcTemplate.update("delete from admin where id = ?", 4);
        System.out.println(rows);
    }

    @Test
    public void testQueryAll(){//查询全部
        RowMapper<Admin> rowMapper = new BeanPropertyRowMapper<Admin>(Admin.class);
        List<Admin> queryResult = jdbcTemplate.query("select * from admin", rowMapper);
        System.out.println(rowMapper);
        System.out.println(queryResult);
    }
    @Test
    public void testQueryOne(){//查询单个
        RowMapper<Admin> rowMapper = new BeanPropertyRowMapper<Admin>(Admin.class);
        Admin admin = jdbcTemplate.queryForObject("select * from admin where id = ?",
                rowMapper, 1);
        System.out.println(rowMapper);
        System.out.println(admin);
    }

    @Test
    public void testQueryCount(){//查询总数
        Long aLong = jdbcTemplate.queryForObject("select count(*) from admin",
                Long.class);
        System.out.println(aLong);
    }
}

SpringMVC拦截器

HandlerInterceptor

<!--    5. 配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
<!--            对那些资源进行拦截操作-->
            <mvc:mapping path="/**" />
            <bean class="com.ytl.interceptor.MyInterceptor1" />
        </mvc:interceptor>
    </mvc:interceptors>

preHandle方法

返回只是一个布尔值,为true时放行

在目标方法执行之前执行
可以在此方法中 请求转发 或 重定向 到其它资源

请求转发

request.getRequestDispatcher("").forward(request, response);

重定向

response.sendRedirect("");

postHandle方法

在目标方法执行之后 视图对象返回之前执行
有 ModelAndView 参数就可以修改返回的数据和视图

afterCompletion方法

在流程结束后执行
可以封装异常,也可以跳转

多个拦截器

顺序是由spring-mvc.xml中的配置顺序

在这里插入图片描述

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession httpSession = request.getSession();
        Object user = httpSession.getAttribute("user");
        if(user instanceof User){
//            request.getRequestDispatcher(request.getRequestURI()).forward(request, response);
            System.out.println("存在user");
            System.out.println(request.getRequestURI());
        }else {
            System.out.println("不存在user");
            response.sendRedirect(request.getContextPath()+"/login.jsp");
            return false;
        }
        //放行,访问资源
        return true;
    }
        <mvc:interceptor>
<!--            对那些资源进行拦截操作-->
            <mvc:mapping path="/**" />
            <!--            对那些资源取消拦截操作-->
            <mvc:exclude-mapping path="/user/login.do" />
            <bean class="com.ytl.interceptor.MyInterceptor1" />
        </mvc:interceptor>

Spring MVC的异常处理

    <!--4、配置异常处理器-->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="defaultErrorView" value="defaultError" />
        <property name="exceptionMappings">
            <map>
                <entry key="java.lang.ClassCastException" value="error1" />
                <entry key="com.ytl.exception.MyException" value="error2" />
            </map>
        </property>
    </bean>
    <!--4、配置自定义异常处理器-->
    <bean class="com.ytl.resolver.MyExceptionResolver" />
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值