java中的控制器_SpringMVC基础(一)_控制器

Spring MVC

Spring MVC 基于模型-视图-控制器(Model-View-Controller)模式实现,它能够帮你构建灵活和松耦合的应用程序。

1、Spring MVC的请求追踪

每当用户在 Web 浏览器中点击链接或提交表单是,请求就开始工作,从离开浏览器开始到获取响应返回,请求在 Spring MVC 框架中会经过以下过程:

127fcdd96e3783c1af8ea2caefa0b963.png

在请求离开浏览器时,会带有用户所请求内容的信息,至少会包含请求的 URL,然后到达前端控制器;

前端控制器会查询一个或多个处理器映射(Handler mapping)来确定访问哪个控制器;

前端控制器将请求发送给指定的控制器;

控制器将模型数据打包,并标示出用于渲染的视图名;

前端控制器使用视图解析器,根据视图名匹配特定的视图实现;

视图将使用模型数据渲染输出,并通过响应对象传递给客户端;

我们已经大概了解了 Spring MVC 的工作流程,但其间涉及到多种组件,它们的任务分别是:

前端控制器:它是一个处理请求的 Spring 组件,所有的请求都会经过它。它的任务主要有:

将请求发给控制器(Controller);

接收控制器返回的请求、模型数据以及视图名;

调用视图解析器匹配一个特定的视图实现;

交付模型数据,将视图输出到浏览器;

处理器映射:根据请求 URL 匹配控制器;

控制器

接收请求数据,完成业务逻辑处理;

将模型数据(业务逻辑处理产生的信息,需要返回显示在浏览器上的信息称为模型数据)打包;

返回一个要渲染的视图名;

视图解析器:根据视图名,匹配对应的一个视图(JSP等)实现返回;

2、Spring MVC配置搭建

DispatcherServlet 是 Spring MVC 的核心,它负责将请求转到其他组件中。但它是一个 Servlet,按照传统方式,需要在 web.xml 文件中配置 DispatcherServlet ,借助 Servlet 3 的规范和 Spring 3.1 的功能增强,我们可以使用 Java 的方式进行配置 DispatcherServlet。

1、基于 Java 配置

package spitter.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**

* 该类继承了 AbstractAnnotationConfigDispatcherServletInitializer ,会自动地配置 DispatcherServlet 和 Spring 应用上下文,Spring应用上下文会位于应用程序的 Servlet 上下文之中;

*/

public class SpitterWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

/*

用来装配非Web组件的bean

*/

@Override

protected Class>[] getRootConfigClasses() {

return new Class[]{RootConfig.class};

}

/*

该方法指定配置类

当 DispatcherServlet 启动时,会创建Spring应用上下文,并加载配置文件或配置类中所声明的 bean。

*/

@Override

protected Class>[] getServletConfigClasses() {

return new Class[]{WebConfig.class};

}

/*

该方法会将一个或多个路径映射到 DispatcherServlet 上

将 DispatcherServlet 映射到 “/”,表示应用的默认Servlet,会处理进入应用的所有请求

*/

@Override

protected String[] getServletMappings() {

return new String[]{"/"};

}

}

package spitter.config;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.servlet.ViewResolver;

import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;

import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import org.springframework.web.servlet.view.InternalResourceViewResolver;

/**

* 该类为Spring MVC配置类,具有以下配置:

* 1、启用Spring MVC;

* 2、启用组件扫描;如果没有启用,Spring 只会找到显式声明在配置类中的控制器;

* 3、配置 JSP 视图解析;如果没有配置,会默认使用 BeanNameViewResolver 解析器;

* 4、配置静态资源的处理;

*/

@Configuration

@EnableWebMvc//启用Spring MVC;

@ComponentScan("spitter.config")

public class WebConfig extends WebMvcConfigurerAdapter {

/*

配置 JSP 视图解析器

*/

@Bean

public ViewResolver viewResolver(){

InternalResourceViewResolver resolver = new InternalResourceViewResolver();

resolver.setPrefix("/views/");

resolver.setSuffix(".jsp");

resolver.setExposeContextBeansAsAttributes(true);

return resolver;

}

/*

配置静态资源的处理

该配置是将对静态资源的请求转发到Servlet容器中默认的Servlet上,

而不是使用 DispatcherServlet 来处理此类请求

*/

@Override

public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){

configurer.enable();

}

}

package spitter.config;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.ComponentScan.Filter;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.FilterType;

import org.springframework.web.servlet.config.annotation.EnableWebMvc;

/**

* 用来装配非Web组件的配置;

*/

@Configuration

@ComponentScan(basePackages = {"spitter"},

excludeFilters = {@Filter(type = FilterType.ANNOTATION,value = EnableWebMvc.class)

})

public class RootConfig {

}

2、基于 XML 配置

基于 Java 配置虽然新颖,但对于初学者很不友好。所以,这里也提供了在 web.xml 中装配核心控制器 DispatcherServlet

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"

version="4.0">

dispatcherServlet

org.springframework.web.servlet.DispatcherServlet

contextConfigLocation

classpath:springMvcConfig.xml

1

dispatcherServlet

/

Spring MVC配置文件:springMvcConfig.xml

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"

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

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop.xsd

http://www.springframework.org/schema/mvc

http://www.springframework.org/schema/mvc/spring-mvc.xsd">

在接下来的实践中,本人是根据 XML 配置的。

3、控制器

3.1 控制器的简单实现

如何创建控制器?如何根据请求路径找到控制器?

声明控制器

在类级别上使用注解 @Controller ,该注解与注解 @Component 作用一样,目标是辅助实现组件扫描;

定义方法

方法内进行请求处理,返回值类型为 String,该字符串为要渲染的视图名,提供给视图解析器进行解析。当然返回值类型也可以是其它类型,稍后再讲。

使用注解 @RequestMapping 设置请求路径映射控制器;

RequestMapping注解:指定方法要处理的请求路径,和细化所处理的HTTP方法等,注解内有以下属性:

name:为此 mapping 设置名称;

path/value:复数形式,限制请求路径匹配时调用;当请求路径与该属性内容匹配,则访问;

可同时在类级别和方法级别标注,相当于两级路径:/类设置路径/方法设置路径;

method:限制请求方法匹配时调用;使用 RequestMethod 枚举的属性;

params:限制请求参数;当请求中包含相同的参数名和相同参数值才匹配;

headers:限制请求头;当请求头中包含相同的请求头才匹配;

下面是一个简单的例子

package spitter.controller;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

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

import org.springframework.web.bind.annotation.RequestMethod;

@Controller

@RequestMapping({"/home"})

public class HomeController {

//访问以下方法的请求路径为:/home/homepage

@RequestMapping(value = {"/homepage"},

method = RequestMethod.GET)

public String home() {

return "home"; // 被Spring MVC解读为要渲染的视图名称

}

}

3.2 传递请求参数到控制器

当请求到控制器,如何将请求中的参数传递到控制器的方法中?Spring MVC提供了请求参数绑定机制。

参数绑定机制

表单中的请求参数都是 key-value 形式的;

Spring MVC绑定请求参数的过程:通过表单提交请求参数,作为控制器中方法参数进行自动绑定的;

支持绑定的数据类型

基本类型参数:包括基本类型和String类型;

POJO 类型参数:实体类,及关联的实体类;

数组和集合类型参数:Array、List和Map集合;

使用要求

基本类型参数:要求请求参数名称与控制器中的方法的形参名称一致(严格区分大小写);

POJO类型参数:要求请求参数名称与 POJO 类中的属性名称一致,而且控制器方法的参数类型是POJO类型;

如果POJO类中关联了其它POJO对象,请求参数名使用:关联POJO对象名.属性名;

集合类型参数:

要求集合类型的请求参数必须在 POJO 中。表单中请求参数名称要和POJO类中的集合属性名称相同。

List使用下标赋值;

Map使用键值对赋值;

接收的请求参数时 JSON 格式数。需要借助注解 @ResponseBody 实现;

在方法传入 HttpServletRequest 对象和 HttpServletResponse 对象获取请求参数和响应结果;

案例

下面是表单数据提交的 JSP 代码,例子中所使用的 POJO 类并未展示。

" >GET方式

用户名:

密码:

用户名:

密码:

金额:

真实姓名:

年龄:

用户:

年龄:

用户:

年龄:

用户:

年龄:

用户:

年龄:

表单提交数据访问的控制器代码

package spitter.controller;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

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

import org.springframework.web.bind.annotation.RequestMethod;

import spitter.pojo.Account;

import spitter.pojo.UserList;

import javax.servlet.ServletContext;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import java.util.Date;

@Controller

@RequestMapping(value = {"/reqParamBind"})

public class ParamController {

/**

* get方式请求参数传递

* @param method 请求参数

* @param num 请求参数

* @return 要解析的视图名称

*/

@RequestMapping(value = {"/get"},method = RequestMethod.GET)

public String reqParamBind(String method,int num){

System.out.println("Method:"+method+"---num:"+num);

return "paramAccept";

}

/**

* post方式请求参数传递

* @param method 请求参数

* @param userName 请求参数

* @param password 请求参数

* @return 要解析的视图名称

*/

@RequestMapping(value = {"/post"},method = RequestMethod.POST)

public String reqParamBind(String method,String userName,String password){

System.out.println("Method:"+method+"---userName:"+userName+"---密码:"+password);

return "paramAccept";

}

/**

* POJO实体类型参数绑定

* @param account POJO类

* @return 要解析的视图名称

*/

@RequestMapping(value = {"/pojoBind"},method = RequestMethod.POST)

public String pojoBind(Account account){

System.out.println(account);

return "paramAccept";

}

/**

* List、Map等集合类型参数绑定

* @param userList 实体类;实体类中封装了List集合和Map集合进行绑定

* @return 要解析的视图名称

*/

@RequestMapping(value = {"/collectionBind"},method = RequestMethod.POST)

public String collectionBind(UserList userList,HashMap){

System.out.println(userList);

return "paramAccept";

}

/**

* 获取Servlet的请求和响应对象

* @param request HttpServletRequest

* @param response HttpServletResponse

* @return 要解析的视图名称

*/

@RequestMapping(value = {"/getReqAndResp"},method = RequestMethod.GET)

public String getReqAndResp(HttpServletRequest request, HttpServletResponse response){

System.out.println(request);

HttpSession session = request.getSession();

System.out.println(session);

ServletContext servletContext = request.getServletContext();

System.out.println(servletContext);

System.out.println(response);

return "paramAccept";

}

}

3.3 自定义类型转换器

正如我们所知,浏览器提交的数据都是以字符串类型传递的,而 Spring MVC 为我们封装好了常用的类型转换器。但有时,依然会有一些特殊情况。比如:日期格式转换。Spring MVC 只接受 yyyy/MM/dd 类型的日期格式;如果换成 yyyy-MM-dd 类型的日期格式就会出现异常;

这是,我们可以自定义一个转换器,请求参数会根据我们定义的格式进行转换。

定义转换器步骤

创建新类,实现 org.springframework.core.convert.converter.Converter 接口;重写 convert 方法,方法中编写类型转换的代码;

在Spring MVC配置文件中,装配 bean 对象 org.springframework.context.support.ConversionServiceFactoryBean;再把刚创建的转换器(bean)填充到该 bean 的属性 converters(为Set集合);

最后,在开启注解支持的标签中,设置 conversion-service 属性,值为 ConversionServiceFactoryBean 的ID值;

案例

转换器类

package spitter.converter;

import org.springframework.core.convert.converter.Converter;

import java.text.DateFormat;

import java.text.SimpleDateFormat;

import java.util.Date;

public class StringToDate implements Converter {

@Override

public Date convert(String source) {

if (source == null && "".equals(source)) {

throw new RuntimeException("请输入数值");

} else {

DateFormat df = new SimpleDateFormat("yyyy-MM-dd");

try {

return df.parse(source);

} catch (Exception e) {

throw new RuntimeException("数据类型转换错误");

}

}

}

}

在 Spring MVC 配置文件进行配置

但是:日期转换器转换 yyyy-MM-dd 类型后,再使用 yyyy/MM/dd类型会出现错误:Bad Request。

3.4 数据传递到视图

控制器方法中处理后的数据信息,如何传递到视图,展示在浏览器?

方法参数中使用接口:org.springframework.ui.Model,它会调用子类 BindingAwareModelMap 对象的 addAttribute(key,value) 方法传递;

也可以使用Map集合,并使用 put 方法进行数据传递;

方法参数传入 HttpServletRequest 对象和 HttpServletResponse 对象进行数据传递;

/*

将控制器的数据传递到视图中

需要传递一个参数:Model或 Map对象,调用对应的addAttribute方法或put方法传递;

*/

@RequestMapping(value = {"/homeParam"}, method = RequestMethod.GET)

public String home(/*Map*/ Model model) {

//model.put("name","Chan");

model.addAttribute("name", "Chan");

return "home";

}

3.5 控制器方法返回值类型

当控制器方法的返回值类型为以下类型时,实现页面跳转的方式:

String类型

Spring MVC 会根据返回的字符串进行视图名称解析,比如:jsp的视图解析后为:路径/字符串.jsp,并跳转到解析后的 JSP 页面;

返回值是void类型

没有返回值时,Spring会默认到视图解析器前缀目录(配置文件中视图解析器前缀为:/views/)下,访问:控制器类路径/方法路径.jsp。

没有返回值时,可以使用原生 Servlet 的请求和响应对象,进行请求转发、重定向,甚至是直接返回数据;

ModelAndView类型

ModelAndView 是 SpringMVC 为我们提供的一个对象,该对象也可以用作控制器方法的返回值;

该对象中有两个常用的方法:

addObject(String key,Object value):将数据以键值对的方式存储到request作用域中;底层也是使用 Model 对象进行传递数据;

setViewName(String viewName):跳转页面,给定视图名称,经过解析器解析;

关键字进行请求转发、重定向;返回值是String类型,字符串内容如下:

forward:URI路径 :请求转发;/ 表示当前项目路径;

redirect:URI路径 :重定向;不需要加项目名称;

案例

package spitter.controller;

import org.springframework.stereotype.Controller;

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

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

@Controller

@RequestMapping(value = {"/returnType"})

public class ReturnTypeController {

/**

* 返回值为字符串

* @return 字符串为要解析的视图名

*/

@RequestMapping(value = "/stringType",method = RequestMethod.GET)

public String stringType(){

return "returnType";

}

/**

* 返回值为 void

*/

@RequestMapping(value = "/voidType",method = RequestMethod.GET)

public void voidType(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

//请求转发

//request.getRequestDispatcher("/index.jsp").forward(request,response);

//重定向

//response.sendRedirect(request.getContextPath()+"/index.jsp");

//直接返回数据

//request.setCharacterEncoding("UTF-8");

//response.setContentType("text/html;charset=utf-8");

//response.getWriter().write("数据...");

}

/**

* 返回值为 ModelAndView 类型

* @return ModelAndView对象

*/

@RequestMapping(value = "/modelAndView",method = RequestMethod.GET)

public ModelAndView modelAndView(){

//创建 modelAndView 对象

ModelAndView modelAndView = new ModelAndView();

//设置Request作用域属性

modelAndView.addObject("name","Chan");

//跳转页面

modelAndView.setViewName("../index");

return modelAndView;

}

@RequestMapping(value = "/forwardOrRedirect")

public String forwardOrRedirect(){

//请求转发

return "forward:/views/page.jsp";

//重定向

//return "redirect:/index.jsp";

}

}

3.6 控制器中常用注解

@RequestParam():将指定的请求参数赋给控制器中的参数;

用于请求参数名称与控制器方法形参名称不一致时,标注在控制器方法的形参前;

value属性:请求参数的名称;

required属性:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错;

/**

* RequestParam注解匹配请求参数名和控制器方法形参名不一致

* @param userName 控制器方法形参名

* @param model 数据传递对象,把数据传递到视图层

* @return 要解析的视图名称

*/

@RequestMapping(value = "/requestParam",method = RequestMethod.GET)

public String requestParam(@RequestParam(value = "uname") String userName, Model model){

}

@RequestBody()

读取 Request 请求的 body 部分数据,直接使用得到是 key=value&key=value... 结构的数据;get 请求方式不适用;

required属性:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值为 false,get 请求得到是 null;

会使用默认配置的 HttpMessageConverter 解析数据,然后把相应的数据绑定到对象上;

@ResponseBody()

将 Controller 的方法返回的对象,通过适当的HttpMessageConverter 转换为指定格式后,写入到Response对象的body 数据区;

@RequestBody() 和 @ResponseBody() 可以接收和响应 JSON 数据。例如:Ajax 请求中,能够接收 JSON 数据封装到对象中,也可以将对象解析为 JSON 数据传送。

@RequestMapping(value = "/ajaxRequest")

public @ResponseBody User ajaxRequest(@RequestBody User user){

user.setRealName("xiaoyao");

user.setAge(30);

return user;

}

@PathVariable():用于从 url 中获取数据

请求 url 中使用占位符标记要获取的数据,例如: /delete/{id},这个 {} 就是 url 占位符;url 支持占位符是 spring3.0 之后加入的;是 spring mvc 支持 rest 风格 URL 的一个重要标志。

value属性:用于指定 url 占位符中名称;

required属性:是否必须提供占位符;

@RequestHeader():用于获取请求消息头;

value属性:提供消息头名称;

required属性:是否必须有此消息;

@CookieValue():用于把指定 cookie 名称的值传入控制器方法参数;

value属性:指定 cookie 的名称;

required属性:是否必须有此 cookie;

@ModelAttribute():可以用于修饰方法和参数;

也就是 Model 对象中 Attribute 操作。

出现在方法上,表示当前方法会在控制器方法执行之前,先执行。方法有返回值则把返回值放到 Model中;

出现在参数上,获取指定的数据赋给方法参数;如果存在表单提交的数据,会优先绑定请求参数;

value属性:获取 Model 中数据的 key 。key 可以是POJO的属性名称,也可以是map结构的 key;

案例:当表单提交的数据不是完整的实体类数据时,为了保证没有提交数据的字段使用数据库对象原来的数据,有数据的字段是不允许修改的,即使用set方法赋值;

![ModelAttribute使用](D:\Coding_WorkSpace\Programmer Course\Note\第六阶段-框架学习\image\ModelAttribute使用.png)

@SessionAttribute():用于多次执行控制器方法间的参数共享;

只能作用在类级别上;将数据存储在Session作用域;

value属性:用于指定存入的属性名称;

type属性:用于指定存入的数据类型;

package spitter.controller;

import org.springframework.stereotype.Controller;

import org.springframework.ui.ExtendedModelMap;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.*;

import org.springframework.web.bind.support.SessionStatus;

import spitter.pojo.User;

import java.io.UnsupportedEncodingException;

@Controller

@RequestMapping(value = {"/anno"})

//(1)将控制器方法中添加到 Model 中的数据存储到Session域。value中指定数据的 key

@SessionAttributes(value = {"session"})

public class AnnoController {

//(2)

@RequestMapping(value = "/setSessionAttr")

public String setSessionAttr(Model model){

model.addAttribute("session","控制器类使用 @SessionAttribute 存储数据");

return "paramAccept";

}

@RequestMapping(value = "/getSessionAttr")

public String getSessionAttr(ExtendedModelMap model){

//(3)获取Session作用域属性

String session = (String) model.get("session");

System.out.println(session);

return "paramAccept";

}

@RequestMapping(value = "/delSessionAttr")

public String delSessionAttr(SessionStatus status){

//(4)清空session域

status.setComplete();

return "paramAccept";

}

}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值