SpringMVC是什么,有多火,我这里就不再啰嗦了,SpringMVC比Struts2好用太多,我在学校的时候私下里两种都接触过,对比之后果断选择了SpringMVC,后来在做Android应用开发的时候,偶尔需要搭建一个后台服务,都是毫不犹豫的选择了SpringMVC作为首选。不过在之前使用SpringMVC的时候都是使用xml文件来进行配置的,那么这里我想换一种方式,通过Java注解来配置SpringMVC框架。OK,废话不多说,那我们就开始吧。对了,如果小伙伴对Spring的基本使用还不太了解,可以先参考这三篇文章:
Spring基础配置
Spring常用配置
Spring常用配置(二)
创建项目
为什么要说项目的创建呢?这是因为我自己之前一直使用STS做Web,后来因为Android Studio做久了,深深地爱上了IntelliJ IDEA,所以Web开发干脆也挪到IntelliJ IDEA上了,不过这个东西做Web还不太熟,掉进了一个项目创建的坑,所以这里稍微说一下项目的创建过程,避免其他小伙伴再掉坑。
1.创建普通Web Application
注意创建的时候取消Create web.xml的选项,因为这里我将不通过xml进行SpringMVC的配置,而是通过注解的方式,后面的就是给项目取名字,然后一路下一步即可。
2.添加Maven支持
项目创建成功之后,选中项目,右键单击,选择第二项Add Framework Support,然后在新打开的页面中选择Maven,点击确定即可,如下:
这样就成功创建了一个被Maven管理的Web项目了。
OK,关于项目创建流程这个问题如果小伙伴们有更好的方式欢迎留言讨论。
添加依赖库
这里涉及到的依赖库略多,我们来看看:
<properties>
<spring-framework.version>4.3.4.RELEASEspring-framework.version>
properties>
<dependencies>
<dependency>
<groupId>javaxgroupId>
<artifactId>javaee-apiartifactId>
<version>7.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${spring-framework.version}version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>${spring-framework.version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.21version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>jcl-over-slf4jartifactId>
<version>1.7.21version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.1.8version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>1.1.8version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-accessartifactId>
<version>1.1.8version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.6.0version>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-war-pluginartifactId>
<version>3.0.0version>
<configuration>
<failOnMissingWebXml>falsefailOnMissingWebXml>
configuration>
plugin>
plugins>
build>
但实际上每个依赖库的用处都是非常清晰的,slf4j和LogBack这两个主要是用来打印日志的,jstl支持页面的创建,这些都是JavaEE中非常常见的库,我就不再赘述了。
创建演示页面
由于这一系列文章,我主要是想介绍Spring Boot的使用,所以这里我把jsp文件创建在src/main/resources/views/目录下。如下图:
在resources目录下还有一个logback.xml文件,这个文件是用来打印日志的,这个文件小伙伴们一会可以直接下载。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello SpringMVCtitle>
head>
<body>
<h1>Welcome to SpringMVC world!h1>
body>
html>
这个jsp页面很简单,只有一行文字。
SpringMVC配置
老子《道德经》第六十四章:“合抱之木,生于毫末;九层之台,起于垒土;千里之行,始于足下。”
这里我们先看SpringMVC中最基本最简单的配置,完了之后我们再来看复杂的配置。
@Configuration
@EnableWebMvc
@ComponentScan("org.sang")
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;
}
}
OK,@EnableWebMvc表示开启SpringMVC中一些默认配置,ViewResolver是SpringMVC视图渲染的核心机制,SpringMVC框架中有一个ViewResolver接口,该接口有一个方法叫做resolveViewName
,该方法返回一个View对象,这个View的职责就是结合request、response对象,将渲染的视图返回给浏览器,渲染后的视图可以是HTML,也可以是json、xml、PDF等。另外,由于项目编译之后运行的时候,index.jsp 文件是处于/WEB-INF/classes/views/目录下的,所以前缀为/WEB-INF/classes/views/。
Web配置
public class WebInitializer implements WebApplicationInitializer {
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);
}
}
这里的代码对照xml配置也都很好理解,首先我们自定义类实现WebApplicationInitializer接口,并实现该接口中的onStartup方法,该方法在Spring容器启动之后就会被自动调用,然后创建AnnotationConfigWebApplicationContext的实例并加载我们的SpringMVC的配置文件,这一步其实也可以通过加载xml文件来完成,当然,这是另外一个话题了。最后创建DispatcherServlet,并设置映射方式以及启动时机等。
创建一个简单控制器
@Controller
@RequestMapping("/index1")
public class HelloController {
@RequestMapping("/index2")
public String hello(HttpServletRequest request) {
System.out.println(request.getParameter("username"));
return "index";
}
}
首先利用@Controller注解声明这是一个控制器,在前面的文章中我们说过@Controller和@Service等可以混用,但是在使用SpringMVC时声明控制器Bean的时候,却只能够使用@Controller;然后利用@RequestMapping来配置URL和方法之间的映射关系,@RequestMapping这个注解我们可以使用在类上,也可以使用在方法上,如果用在方法上,则方法上的路径会继承类上的路径,另一方面,使用了@RequestMapping注解的方法也可以添加request或者response参数。
部署项目并运行
OK,做完上面几个步骤之后我们就可以来运行项目了,我们来看看运行结果:
.
本案例下载地址:
本案例GitHub地址
OK,上面是一个简单的SpringMVC注解配置,可能很多小伙伴看的还不过瘾,那我们再来说说另外几个注解配置。
1.@ResponseBody 这个注解可以让我们将返回值放在response体内,而不是返回一个html页面,当我们在移动端比如Android、或者通过Ajax来访问服务端的数据的时候,就可以通过这个注解。
2.@RequestBody 这个注解允许request的参数在request体中,而不是直接放在地址后面。
3.@PathVariable 这个注解用来接收路径参数
4.@RestController 这是一个组合注解,组合了@Controller和@ResponseBody两个,在开发中我们可以用@RestController这一个,也可以用后面两个,使用这个可以自动将一个对象转为xml或者json返回给客户端。
OK ,结合上面说的这几个注解,我们来看看几个案例。
首先我们来重新创建一个Project,创建方式和上面说的一样,创建成功之后添加依赖,依赖也和上面一致,只不过这里多添加两个,一个是json转化工具类,一个是xml转化工具类。如下(注释中已经列出请求地址以及请求结果):
<dependency>
<groupId>com.google.code.gsongroupId>
<artifactId>gsonartifactId>
<version>2.8.0version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformatgroupId>
<artifactId>jackson-dataformat-xmlartifactId>
<version>2.8.5version>
dependency>
其他的SpringMVC的配置以及Web配置还是和上文一致,接下来我们来我们主要来看看控制器:
@Controller
@RequestMapping("/user")
public class UserController {
//http://localhost:8080/user/
@ResponseBody
@RequestMapping(produces = "text/plain;charset=UTF-8")//produces描述的是响应的头信息的Content-Type字段
public String user(HttpServletRequest request) {
//url:http://localhost:8080/user can access
return "url:" + request.getRequestURL() + " can access";
}
//http://localhost:8080/user/user/张三
@ResponseBody
@RequestMapping(value = "/user/{str}",produces = "text/plain;charset=UTF-8")
public String pathVar(@PathVariable String str, HttpServletRequest request) {
//url:http://localhost:8080/user/user/%E5%BC%A0%E4%B8%89 can access , str is 张三
return "url:" + request.getRequestURL() + " can access , str is " + str;
}
//http://localhost:8080/user/rp?id=100
@ResponseBody
@RequestMapping(value = "/rp",produces = "text/plain;charset=UTF-8")
public String requestParams(long id, HttpServletRequest request) {
//url:http://localhost:8080/user/rp can access , username is :100
return "url:" + request.getRequestURL() + " can access , username is :" + id;
}
//http://localhost:8080/user/json?username=%E5%BC%A0%E4%B8%89&password=123
@ResponseBody
@RequestMapping(value = "/json", produces = "application/json;charset=UTF-8")
public String passObj(UserBean user, HttpServletRequest request) {
Gson gson = new Gson();
//{"username":"张三","password":"123"}
return gson.toJson(user);
}
@ResponseBody
@RequestMapping(value = "/getJson",produces = "application/json;charset=UTF-8")
public UserBean passObj(UserBean userBean) {
return userBean;
}
//http://localhost:8080/user/n1
//http://localhost:8080/user/n2
@ResponseBody
@RequestMapping(value = {"/n1","/n2"},produces = "text/plain;charset=UTF-8")
public String group() {
//不同路径定位到同一方法
return "不同路径定位到同一方法";
}
}
关于这里的方法我说以下几点:
1.方法中的参数是任意的,可以有可以无,也可以有HttpServletRequest和HttpServletResponse类型的参数,使用方式和Servlet中一致。
2.参数可以接收基本数据类型和任何对象。如果是对象,比如我在客户端传递参数时可以传递http://localhost:8080/user/json?username=%E5%BC%A0%E4%B8%89&password=123
,这个时候系统会自动将最后两个参数转为一个UserBean对象交给我。
3.@PathVariable注解可以帮助我们提取请求地址中的字段
4.@RequestMapping注解中的value可以有多个值,这样可以实现多个地址请求到同一个方法。
5.如果想给服务端返回一个json字符串或者xml字符串,直接返回一个对象即可,至于这个对象最终会被转为json还是xml,我们可以通过produces = "application/json;charset=UTF-8"
或者produces = "application/xml;charset=UTF-8"
来定义。
OK,我们也可以使用我们上文提到的组合注解@RestController,使用方式如下:
@RestController
@RequestMapping("/rest")
public class MyRestController {
//http://localhost:8080/rest/getJson?username=%E5%BC%A0%E4%B8%89&password=999
@RequestMapping(value = "/getJson",produces = "application/json;charset=UTF-8")
public UserBean getJson(UserBean userBean) {
return userBean;
}
//http://localhost:8080/rest/getXml?username=%E5%BC%A0%E4%B8%89&password=999
@RequestMapping(value = "/getXml",produces = "application/xml;charset=UTF-8")
public UserBean getXML(UserBean userBean) {
return userBean;
}
}
使用@RestController注解,我们可以避免写@Controller和@ResponseBody。这两个方法返回结果分别如下:
本案例下载地址
本案例GitHub地址
以上。
参考资料:
《JavaEE开发的颠覆者 Spring Boot实战》第四章