第4章:Spring MVC基础(1)

4.1 Spring MVC概述

说到Spring MVC,不得不先来谈谈什么是MVC,它和三层架构是什么关系.可能很多读者都会抢答:
MVC:Model+View+Controller(数据模型+视图+控制器)

三层架构:Presentation tier + Application tier + Data tier(展现层 + 应用层 + 数据访问层)

那MVC和三层架构有什么关系呢?实际上MVC只存在三层架构的展示层,M实际上是数据模型,是包含数据的对象.
在Spring MVC里,有一个专门的类叫Model,用来和V之间的数据交互、传值;V指的是视图页面,包含JSP,freeMarker、Velocity、Thymeleaf、Tile等;C当然是控制器(Spring MVC的注解@Controller的类)

4.2 Spring MVC项目快速搭建

4.2.1 点睛

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

下面我们将基于Maven搭建零配置的Spring MVC原型项目,开发工具相关的内容这里将不再提及

4.2.2 示例

①:构建Maven项目
pom.xml内容:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.guohuai</groupId>
    <artifactId>spring</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jsp.version>2.2</jsp.version>
        <jstl.version>1.2</jstl.version>
        <servlet.version>3.1.0</servlet.version>
        <spring-framework.version>4.1.5.RELEASE</spring-framework.version>
        <loback.version>1.0.13</loback.version>
        <slf4j.version>1.7.5</slf4j.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring-framework.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>${jstl.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servlet.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring-framework.version}</version>
        </dependency>
        <!--使用SLF4J和LogBack作为日志-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${loback.version}</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>${loback.version}</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-access</artifactId>
            <version>${loback.version}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

②:日志配置
在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>
    <jmxConfiguration></jmxConfiguration>
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>logbak:%d{HH:mm:ss.SSS} %logger{36} -%msd%n</pattern>
        </encoder>
    </appender>
    <logger name="org.springframework.web" level="DEBUG"/>
    <root level="info">
        <appender-ref ref="console"/>
    </root>
</configuration>

③:演示页面
在src/main/resources下建立vies目录,并在此目录下新建index.jsp,内容如下

<%@ page language="java" contentType="text/html;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>

代码解释:此处也许会有读者奇怪,为什么页面不放在Maven标准的src/main/webapp/WEB-INF下,此处这样建的主要目的是让大家熟悉Spring Boot的页面习惯的放置方式,Spring Boot的页面就放置在src/main/resources下.

④:Spring MVC配置

package com.wisely.highlight_springmvc4;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@Configuration
@EnableWebMvc
@ComponentScan
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;
    }
}

代码解释:此处无任何特别,只是一个普通的Spring配置类.这里我们配置了一个JSP的ViewResolver,用来映射路径和实际页面的位置,其中,@EnableWebMvc注解会开启一些默认配置,如一些ViewResolver或者MessageConverter等

此处特别解释一下Spring MVC的viewResolver,这是Spring MVC视图(JSP下就是html)渲染的核心机制;Spring MVC里有一个接口叫做ViewResolver(我们的ViewResolver都实现该接口),实现这个接口要重写resolveViewName(),这个方法的返回值是View,而View的职责就是使用model,request,response对象,并将渲染的视图(不一定是html,可能是json、xml、pdf)返回给浏览器.

可能读者对配置的路径前缀为/WEB-INF/classes/views/有些奇怪,怎么和开发的目录不一致?因为看到的页面效果是运行时而不是开发时的代码,运行时代码会将我们的页面自动编译到/WEB-INF/classes/views/下,在Spring Boot中,我们将使用Thymeleaf作为模板,因而不需要这样的配置.

⑤:Web配置

package com.wisely.highlight_springmvc4;


import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

public class WebInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(MyMvcConfig.class);
        ctx.setServletContext(servletContext);
        ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
        servlet.addMapping("/");
        servlet.setLoadOnStartup(1);
    }
}

代码解释:WebApplicationInitializer 是Spring提供用来配置Servlet3.0+配置的接口,从而实现了替代web.xml的位置.实现此接口将会自动被SpringServletContainerInitializer(用来启动servlet3.0容器)获取到.

新建AnnotationConfigWebApplicationContext ,注册配置类,并将其和当前servletContext关联.

注册Spring MVC的DispatcherServlet

⑥:简单控制器

@Controller//1
public class HelloController {

    @RequestMapping("/index")//2
    public  String hello(){

        return "index";
    }

}

⑦:部署到tomcat运行

4.3 Spring MVC的常用注解

4.3.1 点睛

Spring MVC常用以下几个注解
①:@Controller
②:RequestMapping
③:ResponseBody
此注解支持将返回值放在response体内,而不是返回一个页面.我们在很多基于Ajax的程序的时候,可以以此注解返回数据而不是页面;此注解可放置在返回值前或者方法上.
④:@RequestBody
此注解允许request的参数在request体中,而不是在直接连接在地址后面.此注解放在在参数前.
⑤:@pathVariable
@pathVariable用来接收路径参数,如/news/001,可接收001作为参数,此注解放置在参数前
⑥:@RestController
@RestController是一个组合注解,组合了@Controller和@ResponseBody,这就意味着当你只开发一个和页面交互数据的控制的时候,需要使用此注解.若没有此注解,想要实现上述功能,则需自己在代码中加@Controller和@ResponseBody两个注解.

4.3.2 示例

①:添加jsckson及相关依赖,获得对象和json或者xml之间的转换

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.5.3</version>
</dependency>

这里特别指出,在实际项目中,我们其实主要支持json数据,没必要同时支持json和xml,因为json比xml更简洁.由于JavaScript的广泛使用,json成为最推荐的格式,在这种情况下,我们的依赖包如下

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.5.3</version>
</dependency>

此类用来演示获得request对象参数和返回此对象到response:
jackson对对象和json做转换时一定需要此空构造

public class DemoObj {
    private Long id;
    private String name;

    public DemoObj() {
        super();
    }
    public DemoObj(Long id, String name) {
        super();
        this.id = id;
        this.name = name;
    }
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }   
}

②:注解演示控制器

@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, //3
            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";
    }

}

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

③:@Controller演示

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.wisely.highlight_springmvc4.domain.DemoObj;

@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");
    }

}

代码解释:
1.使用@RestController,声明是控制器,并且返回数据时不需要@ResponseBody.
2.返回的数据媒体类型为json
3.直接返回对象,对象会自动转换成json
4.返回数据的媒体类型为xml
5.直接返回对象,对象会自动转换成xml

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值