SpringMVC入门+案例练习

SpringMVC入门+案例练习

一、简介

  • 概念

    SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架。它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful编程风格的请求。

  • 快速入门

    **需求:**客户端发起请求、服务器端接受数据,执行逻辑并进行视图跳转

    步骤(配置方式)

    1.导入SpringMVC相关坐标

    <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.3.8</version>
            </dependency>
        </dependencies>
    

    2.在工程目录下创建web(webapp)工程目录

    创建步骤

    (1)点击idea上面的File,点击project sturcture

在这里插入图片描述

(2)进入后点击Modules(模块),点击项目,再点击项目上面的加号,选择web进行创建

在这里插入图片描述

3.web.xml(在上面我们创建的web工程目录下面)中配置SpringMVC核心控制器DispathcerServlet

<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>

4.在resource包下面创建SpringMVC配置文件(名称随便取,一般命名application.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"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.2.xsd">
    <!--创建容器时要扫码的包-->
    <context:component-scan base-package="com.cqie.controller"></context:component-scan>
    <!--开启注解启动-->
    <mvc:annotation-driven></mvc:annotation-driven>
    <!--    配置视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/page/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>


5.在src/main/java下面创建Controller包,再创建一个HelloSpringController类

@Controller
@RequestMapping("/hello")
public class HelloSpringController {

    @RequestMapping("/spring")
    public String hello(ModelAndView modelAndView){
        System.out.println("hello,spring!");
        //配置有视图解析器,所以直接返回需要跳转的jsp页面名称就可以了
        return "hello.jsp";
    }
}

6.在web文件夹里面WEB-INF里面创建page文件夹,再创建hello.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <p>你好,Spring!</p>
</body>
</html>

7.配置tomcat

配置如下所示

在这里插入图片描述

注意:application context的路径要删掉或者只留一个/,不然等下我们访问的时候会出很多错误,而且后续使用也不方便

8.客户端发起请求

项目启动后我们在浏览器的地址栏输入: localhost:8080/hello

页面出现Hello,Spring就测试成功

  • 执行流程

  1. 用户发送请求至前端控制器DispatcherServlet

  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器

  3. 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

  4. DispatcherServlet调用HandlerAdapter处理器适配器

  5. HandlerAdapter经过适配调用具体的Handler处理器(Controller,也叫后端控制器)。Controller执行完成返回ModelAndView。

  6. HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。

  7. DispatcherServlet将ModelAndView传给ViewReslover视图解析器

  8. ViewReslover解析后返回具体View视图

  9. DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

  10. DispatcherServlet响应用户。

二、SpringMVC组件解析

  • RequestMapping

    • 作用:用于建立请求URL和处理请求方法之间的对应关系
    • 位置
      • 类上,请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录
      • 方法上,请求URL的第二级访问目录,与类上的使用@RequestMapping标注的一级目录一起组成访问虚拟路径
    • 属性:
      • value:用于指定请求的URL。它和path属性的作用是一样的
      • method:用于指定请求的方式
      • params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样
        • 例如:
          • params = {“accountName”},表示请求参数必须有accountName
          • params = {“moeny!100”},表示请求参数中money不能是100
@Controller
@RequestMapping("/hero")
public class HeroController {
    @RequestMapping(value = "/hello",method = RequestMethod.GET,params = {"heroId"})
    public String hello(){
        System.out.println("hello···");
        return "hello.jsp";
    }
}

与RequestMapping组件类似的还有PostMappeing和GetMapping,他们的用法和RequestMapping用法差不多,但是PostMapping不能直接通过地址栏的形式访问要通过表单提交的方式才可以

三、数据响应

  • 页面跳转

    1. 视图解析器

      SpringMVC有默认组件配置,默认组件都是Dispatcherservlet.properties配置文件中配置的,该配置文件地址

      org/springframework/web/ servlet/DispatcherServlet.properties,该文件中配置了默认的视图解析器,如下:

      org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceviewResolver
      

      翻看该解析器源码,可以看到该解析器的默认设置,如下:

      public static final String REDIRECT_URL_PREFIX = "redirect:";  //重定向前缀
      public static final String FORWARD_URL_PREFIX = "forward:";   //请求转发前缀
      
      private String prefix = "";      //视图名称前缀
      private String suffix = "";      //视图名称后缀
      
      <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      	<property name="prefix" value="/WEB-INF/views/"></property>
      	<property name="suffix" value=".jsp"></property>
      </bean>
      
      @Controller
      @RequestMapping("/hero")
      public class HeroController {
          @RequestMapping("/hello")
          public String hello(){
              System.out.println("hello···");
              return "hello";
          }
      }
      
    2. 返回字符串形式
      • **直接返回字符串:**此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转

        资源地址:/WEB-INF/views/hello.jsp

      • 返回带有前缀的字符串

        转发:forward:/WEB-INF/views/hello.jsp

        重定向:redirect:/index.jsp

        @RequestMapping("/forward")
        public String forword(){
        	System.out.println("forward···");
        	return "forward:/WEB-INF/views/index.jsp";
        }
        @RequestMapping("/redirect")
        public String redirect(){
        	System.out.println("redirect···");
        	return "redirect:/login.jsp";
        }
        
    3. 返回ModelAndView对象
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
          你好,SpringMVC!${username}
      </body>
      </html>
      
      	@RequestMapping("/hello2")
          public ModelAndView hello2(){
              //Model:模型,用于封装数据
              //View:视图,用于展示数据
              ModelAndView modelAndView = new ModelAndView();
              modelAndView.addObject("username","pep7chiao");
              modelAndView.setViewName("hello");
              return modelAndView;
          }
      
          @RequestMapping("/hello3")
          public ModelAndView hello3(ModelAndView modelAndView){
              modelAndView.addObject("username","pep7chiao");
              modelAndView.setViewName("hello");
              return modelAndView;
          }
      
          @RequestMapping("/hello4")
          public String hello4(Model model){
              model.addAttribute("username","messi");
              return "hello";
          }
      
          @RequestMapping("/hello5")
          public String hello5(HttpServletRequest reqest){ //HttpServletRequest需要添加依赖
              reqest.setAttribute("username","ronaldo");
              return "hello";
          }
      
  • 回写数据

    1. 直接返回字符串

      Web基础阶段,客户端访问服务器端,如果想直接回写字符串作为响应体返回的话,只需要使用response.getWriter().print(“hello world”))即可,那么在Controller中想直接回写字符串该怎样呢?

      • 通过SpringMVC框架注入的response对象,使用response.getWriter().print(“hello world”)回写数

      据,此时不需要视图跳转,业务方法返回值为void。

      @RequestMapping("/data1")
      public void data1(HttpServletResponse response) throws IOException {
      	response.setContentType("text/html;charset=utf-8");
          response.getWriter().print("重庆工程学院");
      }
      
      • 将需要回写的字符串直接返回,但此时需要通过**@ResponseBody**注解告知SpringMVC框架,方法返回的字符串不是跳

        转,而是直接在http响应体中返回。

      @RequestMapping(value = "/data2",produces = "text/html;charset=utf-8")
      @ResponseBody
      public String data2(){
      	return "软件工程研究所";
      }
      
    2. 返回对象或集合
      • 导入json相关依赖
      		<dependency>
                  <groupId>com.fasterxml.jackson.core</groupId>
                  <artifactId>jackson-databind</artifactId>
                  <version>2.9.0</version>
              </dependency>
      
      • 通过SpringMVC帮助我们对对象或集合进行json字符串的转换并回写,为处理器适配器配置消息转换参数,指定使用jackson进行对象或集合的转换,因此需要在spring-mvc.xml中进行如下配置:
       <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
               <property name="messageConverters">
                   <list>
                       <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                       </bean>
                   </list>
               </property>
       </bean>
    
       @RequestMapping("/data3")
    @ResponseBody
       public Hero data3() throws IOException {
       	Hero hero = new Hero();
       	hero.setId(1L);
    	hero.setHeroName("李白");
       	return hero;
       }
    
    • 在方法上添加@ResponseBody就可以返回json格式的字符串,但是这样配置比较麻烦,配置的代码比较多,因此,我们可以使用mvc的注解驱动代替上述配置。
    <mvc:annotation-driven/>
    
    • 在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。使用<mvc:annotation-driven>自动加载RequestMappingHandlerMapping (处理映射器)和
      RequestMappingHandlerAdapter(处理适配器),可用在Springmvc.xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置。
    • 同时使用<mvc:annotation-driven>默认底层就会集成jackson进行对象或集合的json格式字符串的转换。

四、文件上传

  1. 文件上传客户端三要素

    • 表单项type=“file”
    • 表单的提交方式是post
    • 表单的enctype属性是多部分表单形式,及enctype= “multipart/form-data"
    <form action="${pageContext.request.contextPath}/hero/upload" method="post" enctype="multipart/form-data">
    	<p>名称:<input type="text" name="heroName"></p>
    	<p>图片:<input type="file" name="heroImg"></p>
    	<p><input type="submit" value="提交"></p>
    </form>
    
  2. 文件上传原理

    • 当form表单修改为多部分表单时,request.getParameter()将失效。
    • enctype= “application/x-www-form-urlencoded”时,form表单的正文内容格式是:key=value&key=value&key=value
    • 当form表单的enctype取值为Mutilpart/form-data时,请求正文内容就变成多部分形式(火狐浏览器可查看):
    -----------------------------28609777630614176314163519108
    Content-Disposition: form-data; name="heroName"
    
    11
    -----------------------------28609777630614176314163519108
    Content-Disposition: form-data; name="heroImg"; filename="待办事项.txt"
    Content-Type: text/plain
    
    -----------------------------28609777630614176314163519108--
    
  3. 单文件上传步骤

    (1)导入fileupload和io坐标

    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.2.2</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.4</version>
    </dependency>
    

    (2)配置文件上传解析器

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    	<property name="maxUploadSize" value="5242880"></property>
    	<property name="maxUploadSizePerFile" value="5242880"></property>
    	<property name="defaultEncoding" value="UTF-8"></property>
    </bean>
    

    (3)编写文件上传代码

    @RequestMapping("/upload")
    @ResponseBody
    public void upload(String heroName, MultipartFile heroImg) throws IOException {
    	String originalFilename = heroImg.getOriginalFilename();
    	System.out.println("文件名称:"+originalFilename);
    	heroImg.transferTo(new File("D:\\DevelopWork\\javaweb\\springmvc-demo\\web\\upload\\"+originalFilename));
    }
    
  4. 多文件上传实现

    <form action="${pageContext.request.contextPath}/hero/uploads" method="post" enctype="multipart/form-data">
            <p>名称:<input type="text" name="heroName"></p>
            <p>图片1:<input type="file" name="heroImgs"></p>
            <p>图片2:<input type="file" name="heroImgs"></p>
            <p>图片3:<input type="file" name="heroImgs"></p>
            <p>图片4:<input type="file" name="heroImgs"></p>
            <p><input type="submit" value="提交"></p>
    </form>
    

    或者:

    <form action="${pageContext.request.contextPath}/hero/uploads" method="post" enctype="multipart/form-data">
            <p>名称:<input type="text" name="heroName"></p>
            <p>图片:<input type="file" name="heroImgs" multiple></p>
            <p><input type="submit" value="提交"></p>
    </form>
    
    @RequestMapping("/uploads")
    @ResponseBody
    public void uploads(String heroName, MultipartFile[] heroImgs) throws IOException {
    	for (MultipartFile heroImg : heroImgs) {
    		String originalFilename = heroImg.getOriginalFilename();
    		System.out.println("文件名称:"+originalFilename);
    		heroImg.transferTo(new File("D:\\DevelopWork\\javaweb\\springmvc-demo\\web\\upload\\"+originalFilename));
    	}
    }
    

五、拦截器

  1. 拦截器的作用

    Spring MVC的拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。

    将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(Interceptor Chain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。

  2. 拦截器和过滤器的区别

    区别过滤器拦截器
    使用范围是servlet规范中的一部分,任何Java Web工程都可以使用是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用
    拦截范围在url-pattern中配置了/*之后,可以对所有要访问的资源拦截只会拦截访问的控制器方法,如果访问的是jsp,html,css,image或者js 是不会进行拦截的

3.拦截器基础入门(登录拦截器)

(1)创建interceptor包,在包下创建LoginInterceptor类

package com.cqie.interceptor;

import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //从请求头中获取“Authorization”字段的值
        String authorization = request.getHeader("Authorization");
        if(ObjectUtils.isEmpty(authorization)){
            //设置响应字符编码
            response.setCharacterEncoding("utf-8");
            //设置响应内容为"json"
	     response.setContentType("application/json;charset=utf-8");
            //设置提示信息
            response.getWriter().write("权限不足");
            return false;
        }
        //从会话中获取Authorization字段所对应的值
        HttpSession session = request.getSession();
        Object obj = session.getAttribute(authorization);
        if(ObjectUtils.isEmpty(obj)){
         response.getWriter().write("用户身份已经过期,请重新登录");
         return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

(2)配置拦截器

	<mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/hero/*"/>   
            <mvc:exclude-mapping path="/hero/login"/>
            <bean class="com.cqgcxy.interceptor.LoginIntercepter"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

(3)Controller

	@RequestMapping(value = "/login",method = RequestMethod.GET)
    public String login(){
        return "forward:/login.jsp";
    }

    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public String login(String username, String password, HttpSession session){
        //模拟登录验证
        if("pep".equals(username)&&"123".equals(password)){
            session.setAttribute("username",username);
        }
        return "redirect:/hero/index";
    }

(4)jap页面

<form action="${pageContext.request.contextPath}/hero/login" method="post">
    <p>
      账号:<input type="text" name="username">
    </p>
    <p>
      密码:<input type="text" name="password">
    </p>
    <p>
      <input type="submit" value="登录">
    </p>
</form>

4.拦截器方法说明

方法名说明
preHandle方法将在请求处理之前进行调用,该方法的返回值是布尔值Boolean类型的,当它返回为false时,表示请求结束,后续的Interceptor和Controller都不会再执行;当返回值为true时就会继续调用下一个Interceptor的preHandle方法
postHandle该方法是在当前请求进行处理之后被调用,前提是preHandle方法的返回值为true时才能被调用,且它会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView对象进行操作
afterCompletion该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行,前提是preHandle方法的返回值为true时才能被调用

六、注解模式(常用)

  1. web.xml替换

    public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
        @Override
        protected WebApplicationContext createServletApplicationContext() {
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            ctx.register(SpringMvcConfig.class);
            return ctx;
        }
    
        @Override
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
    
        @Override
        protected WebApplicationContext createRootApplicationContext() {
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            ctx.register(SpringConfig.class);
            return ctx;
        }
        
        @Override
        protected Filter[] getServletFilters() {
            CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
            characterEncodingFilter.setEncoding("UTF-8");
            return new Filter[]{characterEncodingFilter};
        }
    }
    
  2. springmvc.xml替换

    @Configuration
    //@ComponentScan({"com.cqgcxy.controller","com.cqgcxy.service"})
    @ComponentScan("com.cqgcxy.controller")
    public class SpringMvcConfig {
    }
    
  3. applicationContext.xml替换

    @Configuration
    //@ComponentScan({"com.cqgcxy.service","com.cqgcxy.dao"})
    @ComponentScan(value = "com.cqgcxy",
            excludeFilters = @ComponentScan.Filter(
                    type = FilterType.ANNOTATION,
                    classes = Controller.class
            )
    )
    public class SpringConfig {
    }
    

4.配置视图解析器

@Bean
public ViewResolver getViewResolver(){
	InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
	viewResolver.setPrefix("/WEB-INF/views/");
	viewResolver.setSuffix(".jsp");
	return viewResolver;
}

5.配置文件上传解析器

   @Bean
    public MultipartResolver multipartResolver(){
        CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
        commonsMultipartResolver.setMaxUploadSize(5242880);
        commonsMultipartResolver.setMaxUploadSizePerFile(5242880);
        commonsMultipartResolver.setDefaultEncoding("UTF-8");
        return commonsMultipartResolver;
    }

置视图解析器

@Bean
public ViewResolver getViewResolver(){
	InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
	viewResolver.setPrefix("/WEB-INF/views/");
	viewResolver.setSuffix(".jsp");
	return viewResolver;
}

5.配置文件上传解析器

   @Bean
    public MultipartResolver multipartResolver(){
        CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
        commonsMultipartResolver.setMaxUploadSize(5242880);
        commonsMultipartResolver.setMaxUploadSizePerFile(5242880);
        commonsMultipartResolver.setDefaultEncoding("UTF-8");
        return commonsMultipartResolver;
    }
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值