zoukankan      html  css  js  c++  java
  • 四、spring mvc

    4.1 Spring MVC概述

    几个基本概念:

    1. 三层架构: Presentation tier+Application tier+Data tier(展现层+应用层+数据访问层)。
    2. MVC:Model+View+Controller(数据模型+视图+控制器)。
    3. 实际上MVC只存在三层架构的展现层,M实际上是数据模型,是包含数据的对象。
    4. 在Spring MVC里,有一个专门的类叫Model,用来和V之间的数据交互、传值;V指的是视图页面,包含JSP、freeMarker、Velocity、Thymeleaf、Tile等;C当然就是控制器(Spring MVC的注解@Controller的类)。
    5. 三层架构是整个应用的架构,是由Spring框架负责管理的。一般项目结构中都有Service层、DAO层,这两个反馈在应用层和数据访问层

    4.2 Spring MVC项目搭建

    Spring MVC提供了一个DispatcherServlet来开发Web应用。在Servlet 2.5及以下的时候只要在web.xml下配置元素即可。但我们在本节将使用Servlet 3.0+无web.xml的配置方式,在Spring MVC里实现WebApplicationInitializer接口便可实现等同于web.xml的配置。

    4.2.1 示例

    1.构建Maven项目
    2.日志配置
    在src/main/resources目录下,新建logback.xml配置:

    <?xml version="1.0" encoding="UTF-8"?> 
    <configuration scan="true" scanPeriod="1 seconds"> 
        <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"> 
               <resetJUL>true</resetJUL> 
        </contextListener> 
      
        <jmxConfigurator/> 
        
        <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> 
            <encoder> 
                <pattern>logbak: %d{HH:mm:ss.SSS} %logger{36} - %msg%n</pattern> 
            </encoder> 
        </appender> 
        
        <logger name="org.springframework.web" level="DEBUG"/> <!-- 1 --> 
        
        <root level="info"> 
            <appender-ref ref="console"/> 
        </root> 
    </configuration> 
    

    ①将org.springframework.web包下的类的日志级别设置为DEBUG,我们开发Spring MVC经常出现和参数类型相关的4XX错误,设置此项我们会看到更详细的错误信息。

    3.演示界面
    在src/main/resources下建立views目录,并新建index.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8" 
        pageEncoding="UTF-8"%> 
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
    <html> 
    <head> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
    <title>Insert title here</title> 
    </head> 
    <body> 
        <pre> 
            Welcome to Spring MVC world 
        </pre> 
    </body> 
    </html> 
    

    4.Spring MVC配置

    package com.wisely.highlight_springmvc4; 
      
    @Configuration 
    @EnableWebMvc 
    @ComponentScan("com.wisely.highlight_springmvc4") 
    public class MyMvcConfig{ 
        @Bean 
        public InternalResourceViewResolver viewResolver(){ 
            InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); 
            viewResolver.setPrefix("/WEB-INF/classes/views/"); 
            viewResolver.setSuffix(".jsp"); 
            viewResolver.setViewClass(JstlView.class); 
            return viewResolver; 
        } 
    } 
    

    这里我们配置了一个JSP的ViewResolver,用来映射路径和实际页面的位置。
    其中,@EnableWebMvc注解会开启一些默认配置,如一些ViewResolver或者MessageConverter等。
    Spring MVC的ViewResolver,这是Spring MVC视图(JSP下就是html)渲染的核心机制;Spring MVC里有一个接口叫做ViewResolver(我们的ViewResolver都实现该接口)
    前缀配置为/WEB-INF/classes/views/有些奇怪,怎么和我开发的目录不一致?因为看到的页面效果是运行时而不是开发时的代码,运行时代码会将我们的页面自动编译到/WEB-INF/classes/views/下

    5.Web配置

    package com.wisely.highlight_springmvc4; 
    
    public class WebInitializer implements WebApplicationInitializer {//1 
        @Override 
        public void onStartup(ServletContext servletContext) throws ServletException { 
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); 
            ctx.register(MyMvcConfig.class); 
            ctx.setServletContext(servletContext); //2 
            
            Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx)); //3 
            servlet.addMapping("/"); 
            servlet.setLoadOnStartup(1); 
        } 
    } 
    

    ①WebApplicationInitializer是Spring提供用来配置Servlet 3.0+配置的接口,从而实现了替代web.xml的位置。实现此接口将会自动被SpringServletContainerInitializer(用来启动Servlet 3.0容器)获取到。
    ②新建WebApplicationContext,注册配置类,并将其和当前servletContext关联。
    ③注册Spring MVC的DispatcherServlet。

    6.简单控制器

    package com.wisely.highlight_springmvc4.web; 
    
    @Controller//1 
    public class HelloController { 
        
        @RequestMapping("/index")//2 
            public  String hello(){ 
            return "index"; //3 
        }
    } 
    

    ①利用@Controller注解声明是一个控制器。
    ②利用@RequestMapping配置URL和方法之间的映射。
    ③通过上面ViewResolver的Bean配置,返回值为index,说明我们的页面放置的路径为/WEB-INF/classes/views/index.jsp。

    7.运行
    启动Tomcat之后,访问:http://localhost:8080/highlight_springmvc4/index

    4.3 spring MVC常用注解

    (1)@Controller
    @Controller注解在类上,表明这个类是Spring MVC里的Controller,将其声明为Spring的一个Bean,Dispatcher Servlet会自动扫描注解了此注解的类,并将Web请求映射到注解了@RequestMapping的方法上。
    这里特别指出,在声明普通Bean的时候,使用@Component、@Service、@Repository和@Controller是等同的,因为@Service、@Repository、@Controller都组合了@Compoment元注解;但在Spring MVC声明控制器Bean的时候,只能使用@Controller。

    (2)@RequestMapping
    @RequestMapping注解是用来映射Web请求(访问路径和参数)、处理类和方法的。
    @RequestMapping可注解在类或方法上。注解在方法上的@RequestMapping路径会继承注解在类上的路径,@RequestMapping支持Servlet的request和response作为参数,也支持对request和response的媒体类型进行配置。

    (3)@ResponseBody
    @ResponseBody支持将返回值放在response体内,而不是返回一个页面。我们在很多基于Ajax的程序的时候,可以以此注解返回数据而不是页面;此注解可放置在返回值前或者方法上。

    (4)@RequestBody
    @RequestBody允许request的参数在request体中,而不是在直接链接在地址后面。此注解放置在参数前。

    (5)@PathVariable
    @PathVariable用来接收路径参数,如/news/001,可接收001作为参数,此注解放置在参数前。

    (6)@RestController
    @RestController是一个组合注解,组合了@Controller和@ResponseBody,这就意味着当你只开发一个和页面交互数据的控制的时候,需要使用此注解。若没有此注解,要想实现上述功能,则需自己在代码中加@Controller和@ResponseBody两个注解。

    4.3.2 示例

    1.传值类
    添加jackson及相关依赖,获得对象和json或xml之间的转换:

    <!--对json和xml格式的支持 --> 
    <dependency> 
        <groupId>com.fasterxml.jackson.dataformat</groupId> 
        <artifactId>jackson-dataformat-xml</artifactId> 
        <version>2.5.3</version> 
    </dependency> 
    

    此类用来演示获取request对象参数和返回此对象到response:

    package com.wisely.highlight_springmvc4.domain; 
      
    public class DemoObj { 
        private Long id; 
        private String name; 
        
        public DemoObj() { // 1 
            super(); 
        } 
        public DemoObj(Long id, String name) { 
            super(); 
            this.id = id; 
            this.name = name; 
        } 
         get set 省略....
    }
    

    ①jackson对对象和json做转换时一定需要此空构造。

    2.注解演示控制器

    package com.wisely.highlight_springmvc4.web.ch4_3;      
    
    @Controller // 1 
    @RequestMapping("/anno") //2 
    public class DemoAnnoController { 
      
        @RequestMapping(produces = "text/plain;charset=UTF-8")  // 3 
        public @ResponseBody String index(HttpServletRequest request) { // 4 
            return "url:" + request.getRequestURL() + " can access"; 
        } 
      
        @RequestMapping(value = "/pathvar/{str}", produces = "text/plain;charset=UTF-8")// 5 
        public @ResponseBody String demoPathVar(@PathVariable String str, 
                HttpServletRequest request) { 
            return "url:" + request.getRequestURL() + " can access,str: " + str; 
        } 
      
        @RequestMapping(value = "/requestParam", produces = "text/plain;charset=UTF-8") //6 
        public @ResponseBody String passRequestParam(Long id, 
                HttpServletRequest request) { 
            
            return "url:" + request.getRequestURL() + " can access,id: " + id; 
      
        } 
      
        @RequestMapping(value = "/obj", produces = "application/json;charset=UTF-8")//7 
        @ResponseBody //8 
        public String passObj(DemoObj obj, HttpServletRequest request) { 
                 return "url:" + request.getRequestURL() 
                        + " can access, obj id: " + obj.getId()+" obj name:" + obj.getName(); 
      
        } 
      
        @RequestMapping(value = { "/name1", "/name2" }, produces = "text/plain;charset=UTF-8")//9 
        public @ResponseBody String remove(HttpServletRequest request) { 
            
            return "url:" + request.getRequestURL() + " can access"; 
        } 
    } 
    

    ①@Controller注解声明此类是一个控制器。
    ②@RequestMapping(“/anno”)映射此类的访问路径是/anno。
    ③此方法未标注路径,因此使用类级别的路径/anno;produces可定制返回的response的媒体类型和字符集,或需返回值是json对象,则设置produces=“application/json;charset=UTF-8”,在后面的章节我们会演示此项特性。
    ④演示可接受HttpServletRequest作为参数,当然也可以接受HttpServletReponse作为参数。此处的@ReponseBody用在返回值前面。
    ⑤演示接受路径参数,并在方法参数前结合@PathVariable使用,访问路径为/anno/pathvar/xx。
    ⑥演示常规的request参数获取,访问路径为/anno/requestParam?id=1。
    ⑦演示解释参数到对象,访问路径为/anno/obj?id=1&name=xx。
    ⑧@ReponseBody也可以用在方法上。
    ⑨演示映射不同的路径到相同的方法,访问路径为/anno/name1或/anno/name2。

    3.@RestController演示

    package com.wisely.highlight_springmvc4.web.ch4_3; 
      
    @RestController //1 
    @RequestMapping("/rest") 
    public class DemoRestController { 
        
        @RequestMapping(value = "/getjson",produces={"application/json;charset=UTF-8"}) //2 
        public DemoObj getjson (DemoObj obj){ 
            return new DemoObj(obj.getId()+1, obj.getName()+"yy");//3 
        } 
        @RequestMapping(value = "/getxml",produces={"application/xml;charset=UTF-8"})//4 
        public DemoObj getxml(DemoObj obj){ 
            return new DemoObj(obj.getId()+1, obj.getName()+"yy");//5 
        } 
    } 
    

    ①使用@RestController,声明是控制器,并且返回数据时不需要@ResponseBody。
    ②返回数据的媒体类型为json。
    ③直接返回对象,对象会自动转换成json。
    ④返回数据的媒体类型为xml。
    ⑤直接返回对象,对象会自动转换为xml。

    4.4 Spring MVC基本配置

    Spring MVC的定制配置需要我们的配置类继承一个WebMvcConfigurerAdapter类,并在此类使用@EnableWebMvc注解,来开启对Spring MVC的配置支持,这样我们就可以重写这个类的方法,完成我们的常用配置。

    4.1.1 静态资源映射

    程序的静态文件(js、css、图片)等需要直接访问,这时我们可以在配置里重写addResourceHandlers方法来实现。

    示例
    (1)添加静态资源
    在src/main/resources下建立assets/js目录,并复制一个jquery.js放置在此目录下。
    (2)配置代码

    package com.wisely.highlight_springmvc4; 
    
    @Configuration 
    @EnableWebMvc//1 
    @ComponentScan("com.wisely.highlight_springmvc4") 
    public class MyMvcConfig extends WebMvcConfigurerAdapter{//2 
      
        @Bean 
        public InternalResourceViewResolver viewResolver(){ 
            InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); 
            viewResolver.setPrefix("/WEB-INF/classes/views/"); 
            viewResolver.setSuffix(".jsp"); 
            viewResolver.setViewClass(JstlView.class); 
            return viewResolver; 
        } 
        
        @Override 
        public void addResourceHandlers(ResourceHandlerRegistry registry) { 
            registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets/");//3 
        } 
    } 
    

    ①@EnableWebMvc开启SpringMVC支持,若无此句,重写WebMvcConfigurerAdapter方法无效。
    ②继承WebMvcConfigurerAdapter类,重写其方法可对Spring MVC进行配置。
    ③addResourceLocations指的是文件放置的目录,addResourceHandler指的是对外暴露的访问路径。

    4.4.2 拦截器配置

    拦截器(Interceptor)实现对每一个请求处理前后进行相关的业务处理,类似于Servlet的Filter。
    可让普通的Bean实现HanlderInterceptor接口或者继承HandlerInterceptorAdapter类来实现自定义拦截器。
    通过重写WebMvcConfigurerAdapter的addInterceptors方法来注册自定义的拦截器,本节演示一个简单的拦截器的开发和配置,业务含义为计算每一次请求的处理时间。

    示例
    (1)示例拦截器

    package com.wisely.highlight_springmvc4.interceptor; 
    @Override 
        public boolean preHandle(HttpServletRequest request, //2 
                HttpServletResponse response, Object handler) throws Exception { 
            long startTime = System.currentTimeMillis(); 
            request.setAttribute("startTime", startTime); 
            return true; 
        } 
      
        @Override 
        public void postHandle(HttpServletRequest request, //3 HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 
            long startTime = (Long) request.getAttribute("startTime"); 
            request.removeAttribute("startTime"); 
            long endTime = System.currentTimeMillis(); 
            System.out.println("本次请求处理时间为:" + new Long(endTime - startTime)+"ms"); 
            request.setAttribute("handlingTime", endTime - startTime); 
        }
    } 
    

    ①继承HandlerInterceptorAdapter类来实现自定义拦截器。
    ②重写preHandle方法,在请求发生前执行。
    ③重写postHandle方法,在请求完成后执行。

    (2)配置

    @Bean //1 
    public DemoInterceptor demoInterceptor(){ 
        return new DemoInterceptor(); 
    } 
    
    @Override 
    public void addInterceptors(InterceptorRegistry registry) {//2 
        registry.addInterceptor(demoInterceptor()); 
    } 
    

    ①配置拦截器的Bean。
    ②重写addInterceptors方法,注册拦截器。

    4.4.3 @ControllerAdvice

    通过@ControllerAdvice,我们可以将对于控制器的全局配置放置在同一个位置,注解了@Controller的类的方法可使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上,这对所有注解了@RequestMapping的控制器内的方法有效。

    注解 解释说明
    @ExceptionHandler 用于全局处理控制器里的异常。
    @InitBinder 用来设置WebDataBinder,WebDataBinder用来自动绑定前台请求参数到Model中。
    @ModelAttribute @ModelAttribute本来的作用是绑定键值对到Model里,此处是让全局的@RequestMapping都能获得在此处设置的键值对。

    示例
    演示使用@ExceptionHandler处理全局异常,更人性化的将异常输出给用户。

    (1)定制ControllerAdvice。

    package com.wisely.highlight_springmvc4.advice; 
    @ControllerAdvice //1 
    public class ExceptionHandlerAdvice { 
      
        @ExceptionHandler(value = Exception.class) //2 
        public ModelAndView exception(Exception exception, WebRequest request) { 
            ModelAndView modelAndView = new ModelAndView("error");// error页面 
            modelAndView.addObject("errorMessage", exception.getMessage()); 
            return modelAndView; 
        } 
      
        @ModelAttribute //3 
        public void addAttributes(Model model) { 
            model.addAttribute("msg", "额外信息"); //3 
        } 
      
        @InitBinder //4 
        public void initBinder(WebDataBinder webDataBinder) { 
            webDataBinder.setDisallowedFields("id"); //5 
        } 
    } 
    

    ①@ControllerAdvice声明一个控制器建言,@ControllerAdvice组合了@Component注解,所以自动注册为Spring的Bean。
    ②@ExceptionHandler在此处定义全局处理,通过@ExceptionHandler的value属性可过滤拦截的条件,在此处我们可以看出我们拦截所有的Exception。
    ③此处使用@ModelAttribute注解将键值对添加到全局,所有注解的@RequestMapping的方法可获得此键值对。
    ④通过@InitBinder注解定制WebDataBinder。
    ⑤此处演示忽略request参数的id,更多关于WebDataBinder的配置,请参考WebDataBinder的API文档。

    (2)演示控制器

    package com.wisely.highlight_springmvc4.web.ch4_4; 
    
    @Controller 
    public class AdviceController { 
        @RequestMapping("/advice") 
        public String getSomething(@ModelAttribute("msg") String msg,DemoObj obj){//1 
            throw new IllegalArgumentException("非常抱歉,参数有误/"+"来自@ModelAttribute:"+ msg); 
        }
    } 
    

    4.5 Spring MVC的高级配置

    4.5.1 文件上传配置

    Spring MVC通过配置一个MultipartResolver来上传文件。
    在Spring的控制器中,通过MultipartFile file来接收文件,通过MultipartFile[]files接收多个文件上传。

    示例
    (1)添加文件上传依赖。

    <!-- file upload --> 
    <dependency> 
        <groupId>commons-fileupload</groupId> 
        <artifactId>commons-fileupload</artifactId> 
        <version>1.3.1</version> 
    </dependency> 
    <!-- 非必需,可简化I/O操作 --> 
    <dependency> 
        <groupId>commons-io</groupId> 
        <artifactId>commons-io</artifactId> 
        <version>2.3</version> 
    </dependency> 
    

    (2)上传页面。
    在src/main/resources/views下新建upload.jsp。

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
    <html> 
    <head> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
    <title>upload page</title> 
    </head> 
    <body> 
    <div class="upload"> 
        <form action="upload" enctype="multipart/form-data" method="post"> 
            <input type="file" name="file"/><br/> 
            <input type="submit" value="上传"> 
        </form> 
    </div> 
    </body> 
    </html> 
    

    (3)添加转向到upload页面的ViewController

    @Override 
    public void addViewControllers(ViewControllerRegistry registry) { 
        registry.addViewController("/index").setViewName("/index"); 
        registry.addViewController("/toUpload").setViewName("/upload"); 
    } 
    

    (4)MultipartResolver配置

    @Bean 
    public MultipartResolver multipartResolver() { 
        CommonsMultipartResolver multipartResolver =new CommonsMultipartResolver(); 
        multipartResolver.setMaxUploadSize(1000000); 
        return multipartResolver; 
    } 
    

    (5)控制器。

    package com.wisely.highlight_springmvc4.web.ch4_5; 
    
    @Controller 
    public class UploadController { 
        @RequestMapping(value = "/upload",method = RequestMethod.POST) 
        public @ResponseBody String upload(MultipartFile file) {//1 
            try { 
                FileUtils.writeByteArrayToFile(new File("e:/upload/"+file.getOriginalFilename()), 
                        file.getBytes()); //2 
                return "ok"; 
            } catch (IOException e) { 
                e.printStackTrace(); 
                return "wrong"; 
            } 
    } 
    } 
    

    ①使用MultipartFile file接受上传的文件。
    ②使用FileUtils.writeByteArrayToFile快速写文件到磁盘。

  • 相关阅读:
    Node快速安装
    PHP实现简单的监控nginx日志文件功能
    解决linux crontab PHP fgetcsv 读取中文数据为空问题
    Linux查看系统信息命令汇总
    分享一个Mongodb PHP封装类
    Redis PHP通用类
    ubuntu安装php mcrypt扩展
    終端機的環境設定: stty, set
    MySQL Got fatal error 1236原因和解决方法
    bash 的進站與歡迎訊息: /etc/issue, /etc/motd
  • 原文地址:https://www.cnblogs.com/phtjzzj/p/7590717.html
Copyright © 2011-2022 走看看