Spring整合Web开发
- 首先我们需要将环境搭好,因为需要是Spring + web,对应的步骤是:
File -> Project Structure -> Modules -> 点击+
,new Module -> 选择maven,并勾选右边的Create from archetype,然后再点击下面的maven-archetype-webapp即可 -> next ,之后就来到了这一步
然后Name,Location,GroupId根据自己的需要进行修改,再次点击next,之后直接点击finish即可.
-
导入相应的依赖
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.10.RELEASE</version> </dependency>
-
在webapp/WEB-INF目录下创建Spring的核心配置文件applicationContext.xml,当然也可以放在resources目录下面
<?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"> <context:component-scan base-package="day5.demo"></context:component-scan> </beans>
-
创建UserDao,UserService接口,并且创建他们的实现子类UserDaoImpl,UserServiceImpl
public interface UserDao { public void save(); } @Repository("userDao") //相当于<bean id="userDao" class="xxxx"></bean> public class UserDaoImpl implements UserDao { @Override public void save() { System.out.println("UserDao is saving....."); } } public interface UserService { public void save(); } @Service("userService") public class UserServiceImpl implements UserService { @Autowired @Qualifier("userDao") private UserDao userDao; @Override public void save() { userDao.save(); } }
-
创建UserServlet类进行测试
public class UserServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ApplicationContext application = new AnnotationConfigApplicationContext(SpringMVCConfiguration.class); UserService userService = application.getBean("userService", UserService.class); userService.save(); //输出UserDao is saving.... } }
同时我们需要在web.xml中配置对应的Servlet:
<!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> <servlet> <servlet-name>UserServlet</servlet-name> <servlet-class>day5.demo.web.servlets.UserServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UserServlet</servlet-name> <url-pattern>/UserServlet</url-pattern> </servlet-mapping> </web-app>
但是这时候我们如果有多个Servlet,那么每次都需要写下面2步:
ApplicationContext application = new AnnotationConfigApplicationContext(SpringMVCConfiguration.class);
UserService userService = application.getBean("userService", UserService.class);
所以为了每次调用方法的时候,不需要执行这2步,Spring就考虑在tomcat服务器启动的时候,将application这个对象保存到ServletContext域中,然后如果需要获取ApplicationContext对象的时候,就可以从ServletContext中调用getAttribute(“xxx”)方法获得。
而要想tomcat服务器启动的时候,将application对象保存到ServletContext,那么就需要利用ContextLoaderListener监听器来实现,一旦tomcat服务器启动,那么就会触发它的初始化方法,这时候我们就要在这个方法中将application保存到ServletContext域中即可。
而我们创建application对象的时候,还需要知道核心配置文件的名字。那么这时候我们可以通过在web.xml中通过<context-param></context-param>
来定义全局初始化变量。
但是可能会由于ServletContext调用getAttribute(“xxx”)获取ApplicationContext对象的时候,xxx值会忘记,所以我们可以交给WebApplicationContextUtils调用getWebApplicationContext(ServletContext)来获得application对象。而要利用WebApplicationContextUtils,则需要导入依赖spring-web,但是由于我们已经导入了spring-webmvc,所以不用在导入依赖spring-web了.
所以这时候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>
<!--全局初始化变量:Spring核心配置文件-->
<param-name>applicationContext</param-name> <!--可以任意写-->
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<!--
添加监听器ContextLoaderListener,这样就会在web启动/销毁的时候,
就会触发监听事件
-->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>day5.demo.web.servlets.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/UserServlet</url-pattern>
</servlet-mapping>
</web-app>
对应的UserServlet代码为:
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
ApplicationContext application = WebApplicationContextUtils.getWebApplicationContext(servletContext);
UserService userService = application.getBean("userService", UserService.class);
userService.save();
}
}
Spring MVC快速入门
首先要入门Spring MVC,需要先搭建好它的环境,而他的环境搭建和Spring整合Web的环境搭建步骤一样。当环境搭建好之后,就可以快速入门了,测试案例的基本步骤为:
- 导入spring-mvc的依赖,但是由于上面搭建环境中已经导入了spring-webmvc依赖,所以这一步可以不用进行了
- 配置spring的前端控制器DispatcherServlet,和配置其他的Servlet一样是在web.xml中进行配置
- 创建controller,并且将controller添加到Spring容器中。因为是在controller层,所以这时候我们既可以使用注解@Component,也可以使用@Controller注解,从而将对应的controller类添加到Spring容器中
- 利用注解@RequestMapping或者@GetMapping或者@PostMapping,根据url,映射到某一个controller类中的某一个方法.例如@RequestMapping(“/quick”),如果url为
localhost:8080/quick
,那么就会映射到这个注解作用的方法中 - 要执行对应的controller类,那么我们需要扫描组件。所以我们需要创建spring-mvc.xml这个配置文件,然后在这个配置文件中利用context命名空间,来进行组件扫描
对应的UserController代码为:
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/quick") //当请求的参数试quick的时候,那么就会执行这个方法
//如果再类的上面也是用@RequestMapping,那么url是/user/quick的时候,才会映射到当前这个类的save方法
//这时候,返回值就会在/user/success.jsp中寻找这个文件,然后如果没有,就会发生了报错
//所以需要再success.jsp的前面加上/,表示再当前的路径下面
public String save(){
System.out.println("UserController save is running......");
return "/success.jsp";//前端返回到这个页面
}
//@RequestMapping(value="/test1", method= RequestMethod.GET)
@GetMapping("/test1")
//method参数表示请求的方法是GET的时候才会和当前的方法映射,否则不会
//此时就相当于@GetMapping("/test1"),同样的,如果method的值是POST,那么相当于@PostMapping
public String test1(){
System.out.println("UserController test is running......");
return "/success.jsp";
}
@GetMapping(value="/test2",params={"username","age"})
//使用参数params,表示希望请求的url地址中必须要有参数名为username,age
//否则就会发生报错
public String test2(){
System.out.println("UserController test2 is running........");
return "/success.jsp";
}
}
对应的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">
<!--
利用context命名空间,context:component-scan进行组件扫描
而因为已经有了spring来扫描其他层的组件了,所以需要spring mvc来
扫描controller层的组件
-->
<context:component-scan base-package="day5.demo.controller"></context:component-scan>
<!--
视图配置文件,可以配置视图名称的前缀以及后缀
这样再方法的返回值中就可以不用这样写:/success.jsp
或者/jsps/success.jsp了(success.jsp文件再jsps目录下面)
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
-->
</beans>
对应的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>
<!--配置Spring MVC的前端控制器-->
<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>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<!--对于所有的请求,都会经过这个DispatcherServlet-->
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
当我们输入localhost:8080/user/quick1
,那么就会来到了success.jsp页面了,执行的是UserController中的save方法:
Spring MVC的数据响应
Spring MVC页面跳转
在Spring MVC中,如果需要进行页面跳转,主要有2种方式:
-
直接返回一个字符串,其中这个字符串是表示跳转页面对应的文件,如jsp文件。当然也可以是对应文件的名字,只是这时候我们需要在spring-mvc.xml中配置内部资源解析器,来设置属性prefix,sufix即可.
-
直接返回一个ModelAndView对象,并且可以调用addObject方法,来添加数据,如果需要在页面中获取这个数据,那么可以通过spring表达式
${xx}
来获得,调用setViewName(“xxx”),从而跳转到xxx这个页面中。但是,如果最后发现,利用
${yyy}
(spring表达式)没有获取到addObject中添加的数据的值,那么是因为在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" >
改成
<?xml version="1.0" encoding="UTF-8" ?>
即可.
对应的代码为:
@Controller
public class ControllerTest2 {
@RequestMapping("/quick1")
public String test1(){
return "success.jsp"; //直接跳转到success.jsp中
}
@RequestMapping("/quick2") //通过ModelAndView进行页面跳转
public ModelAndView test2(ModelAndView modelAndView){
//我们不需要向这个方法传递参数,因为Spring会帮我们注入
//将username添加到页面中,如果需要在页面中显示,可以通过spring表达式显示${username}
modelAndView.addObject("username","小希");
//将跳转到哪一个页面中
modelAndView.setViewName("success2.jsp");
return modelAndView;
}
}
success.jsp的代码为:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>spring mvc快速入门</title>
</head>
<body>
<h1>
spring mvc的快速入门的基本步骤:<br>
1、导入spring-mvc依赖.但是如果导入了spring-webmvc,那么可以不用再导入spring-mvc依赖<br>
2、创建spring的前端控制器DispatcherServlet.即在web.xml中配置即可<br>
3、创建controller<br>
4、通过使用注解,来将controller中的方法和请求产生映射@RequestMapping
或者@GetMapping、@PostMapping<br>
5、创建spring-mvc的配置文件spring-mvc.xml,进行组件扫描@ComponentScan<br>
6、做出响应<br>
</h1>
</body>
</html>
success2.jsp的代码为:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>通过ModelAndView实现页面跳转</title>
</head>
<body>
<span>
通过ModelAndView实现页面跳转。并且可以通过ModelAndView调用addObject<br>
方法来封装数据。然后在页面中通过spring表达式${xxx}来获得.
</span>
<span>你好呀! </span>
<h1>${username}</h1> <!--Spring表达式,来获取username的值-->
</body>
</html>
如果url是localhost:8080/quick1
,那么前端界面是success.jsp的内容:
如果url是localhost:8080/quick2
,那么前端界面success2.jsp的内容:
而通过返回ModelAndView对象进行页面跳转还有其他的形式,我们可以直接通过new ModelAndView()来创建ModelAndView对象,而上面中则是通过Spring MVC注入的。也可以返回一个字符串,但是通过参数Model调用addAttribute来添加数据。所以对应的代码是:
@RequestMapping("/quick3")
//通过返回ModelAndView对象实现页面跳转,然后调用addObject来添加数据,调用setViewName来设置跳转的页面
public ModelAndView test3(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("username","大大怪");
modelAndView.setViewName("success2.jsp");
return modelAndView;
}
@RequestMapping("/quick4")
//通过返回字符串来实现页面跳转,但是它可以通过Model调用addAttribute来添加数据到页面中
public String test4(Model model){
//通过Model来封装数据,然后返回字符串,跳转到对应的页面中
//此时model时调用addAttribute来添加数据的
model.addAttribute("username","小小怪");
return "success2.jsp";
}
当输入localhost:8080/quick3
,运行结果为:
输入localhost:8080/quick4
,运行结果为:
Spring MVC回写数据
Spring MVC回写数据,主要是回写字符串,或者一个集合或者数组。
如果需要回写的是一个字符串,主要有2种方式:
-
我们在web开发中是通过response调用getWriter获取对应的Writer对象,然后再调用对应的方法进行响应,例如
response.getWriter().println("xxxxx")
,那么我们就可以会写了xxxx字符串了。但是显然我们上面的controller中的方法中没有HttpServletResponse对象,所以我们可以像上面的ModelAndView那样,通过Spring MVC来注入HtttpServlertResponse,然后就可以执行response.getWriter().println("xxxxx")
代码进行回写数据了。此时,方法没有返回值,所以应该是void.这时候如果响应的数据中含有中文,那么就可能会出现乱码问题。所以这时候和web开发解决响应乱码的方法是一样的的,可以通过response调用setContextType(“text/html;charset=utf-8”)来解决. -
我们可以直接返回字符串,但是这时候会被Spring MVC认为是需要进行页面跳转,然后可能就会发生报错,因为这个字符串对应的页面并没有存在。所以为了告诉给Spring MVC知道,这个字符串是用于回写数据的,那么我们就需要再方法的上方使用注解@ResponseBody,这样Spring MVC就知道这个字符串适用于回写数据的.
但是值得注意的是,@ResponseBody来回写数据的时候,需要注意编码的问题,如果返回的是一个对象,那么使用的UTF-8编码,但是如果是String类型,那么Spirng中默认的是ISO-8859编码,所以我们需要在注解@RequestMapping中设置produces的值为text/html;charset=utf-8,也即@RequestMapping(value=“/xxx”,produces={“text/html;charset=utf-8”})即可解决回写数据为String的时候,使用@ResponseBody中文乱码的问题.其中produces的值还有"application/json;charset=utf-8",同样可以解决乱码的问题,但是返回的字符串将是json格式
对应的代码为:
@RequestMapping("/quick5")
public void test5(HttpServletResponse response) throws IOException {
//此时因为考虑到响应的编码问题,所以需要通过response
// 调用setContentType("text/html;charset=utf-8")来解决响应中文乱码问题
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("通过response调用getWriter().println()来进行回写数据的");
}
@RequestMapping(value="/quick6",produces={"text/html;charset=utf-8"})
@ResponseBody
public String test6(){
return "通过使用@ResponseBody,告诉Spring MVC,这个字符串用于回写数据的";
}
当在搜索栏输入localhost:8080/quick5
时,运行结果为:
在搜索栏输入localhost:8080/quick6
时,运行结果为:
如果我们希望将对象或者集合变成json格式的字符串回写,那么我们可以直接返回这个对象,此时交给Spring MVC自动将对象转成json格式的字符串,我们也可以手动的将对象转成对应的json格式的字符串来回写数据。
-
手动将对象或者集合转成json格式的字符串
要通过手动将对象或者集合转成json格式的字符串,那么我们需要导入相应的依赖:jackson-core,jackson-databind,jackson-annotations
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.6</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.6</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.6</version> </dependency>
然后我们创建ObjectMapper对象,通过objectMapper对象调用writeValueAsString(”xxxx"),就可以将xxxx对象转成json格式的字符串,然后我们就可以利用@ResponseBody注解,来回写数据了。同样的,考虑到中文编码的问题,我们需要设置@RequestMapping中的属性produces的值为
text/html;charset=utf-8
解决乱码问题。对应的代码为:
@RequestMapping(value="/quick7",produces={"text/html;charset=utf-8"}) @ResponseBody //告诉Spring mvc框架,返回的字符串适用于回写的,不是用于页面跳转 public String test7() throws JsonProcessingException { User user = new User(); user.setName("小王"); user.setAge(19); ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(user); return json; } @RequestMapping(value="/quick8",produces={"text/html;charset=utf-8"}) @ResponseBody public String test8() throws JsonProcessingException { List<User> lists = new ArrayList<>(); User user1 = new User(); user1.setName("小李"); user1.setAge(19); User user2 = new User(); user2.setName("小孟"); user2.setAge(20); lists.add(user1); lists.add(user2); ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(lists); return json; }
当搜索栏输入
localhost:8080/quick7
时,测试结果:
输入的是
localhost:8080/quick8
时,测试结果为:
如果这时候我们@RequestMapping的属性produces的值为
application/json;charset=utf-8
,那么原本就已经是json格式的字符串,就会变成了下面的字符串:
此时,为了将它的格式变成上面的格式,那么我们需要在spring-mvc.xml中配置处理器适配器,让它的messageConverter的元素含有StringHttpMessageConverter。<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean> </list> </property> </bean>
此时输出结果就可以恢复到和@RequestMapping(produce=“text/html;charset=utf-8”)一样的结果了。
-
利用Spring MVC自动将对象或者集合转成json格式的字符串
如果我们希望直接返回的是一个对象或者集合,然后由Spring MVC来将对象或者集合自动转成json格式的字符串,那么我们同样是在spring-mvc.xml中配置处理器适配器,让他的属性messageConverter中的元素含有MappingJackson2HttpMessageConverter,这样就会将对象转成json格式的字符串了,对应的代码为:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean> <bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean> </list> </property> </bean>
这样我们直接返回对象或者集合的时候,会将自动将对象变成json格式的字符串,但是由于返回的是字符串,默认是进行页面跳转,所以依旧需要使用注解@ResponseBody,告诉Spring MVC转成的字符串是用来回写数据的,代码如下所示:
@RequestMapping(value="/quick9",produces={"text/html;charset=utf-8"}) @ResponseBody public User test9(){ User user = new User(); user.setName("小王"); user.setAge(19); return user; } @RequestMapping(value="/quick10",produces={"text/html;charset=utf-8"}) @ResponseBody public List<User> test10(){ List<User> lists = new ArrayList<>(); User user1 = new User(); user1.setName("小李"); user1.setAge(19); User user2 = new User(); user2.setName("小孟"); user2.setAge(20); lists.add(user1); lists.add(user2); return lists; }
然后输入
localhost:8080/quick9
还是输入localhost:8080/quick10
,运行结果都是下面的样子,提示No converter for [class day5.demo.domain.User] with preset Content-Type 'null'
这时候我们需要将@RequestMapping中的属性produces的值改为
application/json;charset=utf-8
即可解决问题,不可以是produces={"text/html;charset=utf-8","application/json;charset=utf-8"}
,否则还是会发生报错.修改之后的运行结果如下所示:
而我们配置处理器适配器,都需要在spring-mvc.xml中写一大串的代码,所以为了解决这个问题,我们可以使用mvc注解驱动
<mvc:annotation-driven/>
,同样需要使用到了mvc命名空间,而使用mvc命名空间和使用context命名空间一样.所以对应的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:mvc="http://www.springframework.org/schema/mvc" 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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="day5.demo.controller"></context:component-scan> <!-- 使用mvc命名空间,需要加入xmlns:mvc="http://www.springframework.org/schema/mvc"这一串 同时xsi:schemaLocation中同时添加http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd --> <mvc:annotation-driven/> </beans>
这样就可以实现和上面配置处理器适配器的代码是一样的效果。