SpringMVC常用配置-Controller中的各种配置(基于Java API和注解)

 

1、本文内容
2、控制器的声明
  2.1、启用组件自动扫描
  2.2、使用 @Controller 标注
3、映射请求路径
  3.1、在类上使用 @RequestMapping 声明
  3.2、在方法上使用 @RequestMapping 声明
  3.3、@GetMapping、@PostMapping、@PutMapping 等
4、获取 URL 请求参数
  4.1、利用请求路径获取参数 URI Template Pattern & @PathVariable
  4.2、获取 URL 请求参数 @RequestParam
5、获取表单数据
6、控制器返回视图
  6.1、返回视图
  6.2、携带数据返回视图
7、控制器转跳
  7.1、控制器之间跳转
  7.2、跳转到外部链接

 

1、本文内容

Controller 是由很多内容组成的,包括将一个类配置为控制器、将类或方法映射为请求路径、从 URL 请求中解析参数、从表单中解析参数、控制器之间的跳转、请求的重定向、返回视图、构造模型等等内容
本文对这些控制器的常用部分做一个大致的梳理
本文的内容主要基于 Java API 和注解方式配置


2、控制器的声明

2.1、启用组件自动扫描

Spring 配置中的启用组件自动扫描配合使用,将控制器所在的包设置为自动扫描的目标目录

package com.oolong.config;
 
import com.oolong.controller.ControllerScanHook;
 
@Configuration
@EnableWebMvc
@ComponentScan(basePackageClasses={ControllerScanHook.class})
public class WebConfig extends WebMvcConfigurerAdapter { }

 

2.2、使用 @Controller 标注

package com.oolong.controller;
 
import org.springframework.stereotype.Controller;

@Controller
public class HomeController {
 
}

 

3、映射请求路径


3.1、在类上使用 @RequestMapping 声明

这相当于给这个控制器中的所有方法定义一个跟路径,然后在其方法上使用 @RequestMapping 配置映射时,所有的映射都是相对于类声明上配置的这个跟路径的相对路径

@Controller
@RequestMapping("/appointments")
public class AppointmentsController {
    private final AppointmentBook appointmentBook;
 
    @Autowired
    public AppointmentsController(AppointmentBook appointmentBook) {
        this.appointmentBook = appointmentBook;
    }
 
    @RequestMapping(method = RequestMethod.GET)
    public Map<String, Appointment> get() {
        return appointmentBook.getAppointmentsForToday();}
 
    @RequestMapping(path = "/{day}", method = RequestMethod.GET)
    public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso = ISO.DATE)Date day, Model model) {
        return appointmentBook.getAppointmentsForDay(day);
    }
 
    @RequestMapping(path = "/new", method = RequestMethod.GET)
    public AppointmentForm getNewForm() {
        return new AppointmentForm();}
 
    @RequestMapping(method = RequestMethod.POST)
    public String add(@Valid AppointmentForm appointment, BindingResult result) {
        if (result.hasErrors()) {
            return "appointments/new";
        }
        appointmentBook.addAppointment(appointment);
        return "redirect:/appointments";
    }
}

观察这个案例中的内容,当使用 @RequestMapping 标注在类上面声明了一个路径之后,方法的配置分为这样几种情况:

1)GET 方式请求路径“/appointments”,将会进入 get() 方法
2)POST 方式请求路径“/appointments”,将会进入 add() 方法
3)GET 方式请求“/appointment/new”,将会进入 getNewForm() 方法
4)GET 方式请求“/appointment/2016-12-06”,将会进入 getForDay() 方法【参考路径模版】

3.2、在方法上使用 @RequestMapping 声明

在上面的例子中 @RequestMapping 用在了两个地方,首相在类上声明,作为一个“基础”路径,然后在方法上的声明是相对于这个基础路径的相对路径。

除了这种用法,还可以不在类上面标注 @RequestMapping,而直接在方法上使用,这就表示绝对路径的声明,例如下面这样:

@Controller
public class HomeController {
 
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home() {
        return "home";
    }
@RequestMapping(value </span>= "/welcome", method =<span style="color: rgba(0, 0, 0, 1)"> RequestMethod.GET)
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String welcome() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> "welcome"<span style="color: rgba(0, 0, 0, 1)">;
}

}

1)GET 方式请求“/”,就会进入 home() 方法
2)GET 方式请求“/welcome”,就会进入 welcome() 方法

3.3、@GetMapping、@PostMapping、@PutMapping 等

Spring 框架从 4.3 开始引入了一个简化 @ReuqestMapping 的注解,也就是:
@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping

这几个注解实际上就是设置了请求类型的 @RequestMapping 注解,与其对应关系可以参考下面的示例:

@RequestMapping(method = RequestMethod.GET)
@GetMapping
 
@RequestMapping(path = "/new", method = RequestMethod.GET)
@GetMapping("/new")
 
@RequestMapping(method = RequestMethod.POST)

@PostMapping

 

4、获取 URL 请求参数

4.1、利用请求路径获取参数 URI Template Pattern & @PathVariable

在使用 @RequestMapping 或者 @GetMapping 等注解标注映射时,可以使用 URL Template Patterns 来设置请求路径,并从中获取参数。

例如,下面是一个 URI 的模版:

http://www.example.com/users/{userId}

注意这个模版,看起来与普通的 URL 没有什么区别,但是仔细看,其路径的最后一部分是 {userId} ,这样一个使用大括号括起来的字符串,这个就是一个 URI 模版,与这个模版对应的实际请求如下:

http://www.example.com/users/12345

在 SpringMVC 中,对于在 @RequestMapping 中配置的这种请求路径,可以使用 @PathVariable 注解来获取值:

@GetMapping("/owners/{ownerId}")
public String findOwner(@PathVariable String ownerId, Model model) {
Owner owner </span>=<span style="color: rgba(0, 0, 0, 1)"> ownerService.findOwner(ownerId);
model.addAttribute(</span>"owner"<span style="color: rgba(0, 0, 0, 1)">, owner);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> "displayOwner"<span style="color: rgba(0, 0, 0, 1)">;

}

在这个例子中的 URI 路径模版就是“/owners/{ownerId}”,然后在控制器方法的参数中使用 @PathVariable 注解标注一个参数,Spring MVC 就会在获取请求 i 之后自动的将 {ownerId} 所表示的内容设置到这个参数中了。
注意,这里方法的参数名称要与 URI 中的 {var} 名称一样。

此外,@PathVariable 注解可以指定方法参数对应的 URI 模版中占位符的名称:

@GetMapping("/owners/{ownerId}")
public String findOwner(@PathVariable("ownerId")String theOwner, Model model) {
    // implementation omitted

}

 

4.2、获取 URL 请求参数 @RequestParam

利用 @RequestParam 可以从传统的 URL 中获取参数

@RequestMapping(value = "/requestparam", method = RequestMethod.GET)public String acceptingRequestInput(@RequestParam("bookname") String name, @RequestParam("count") int count) {
    System.out.println("bookname:" + name);
    System.out.println("count:" + count);
    return "requestInput";

}

注意这个方法的参数,这个方法有两个参数,分别使用 @RequestParam 注解进行标注了,参考上一小节从路径中获取参数的方式,应该能够联想到这种方式是如何获取参数的。
对应于这个方法的请求路径:

/requestparam?bookname=thinkingjava&count=5

这种传统的 URL 请求,一个“?”后面跟着若干个键值对参数,可以使用 @RequestParam 的方式获取参数。

 

5、获取表单数据

获取表单数据可以直接在控制器中的方法中给出一个模型作为参数即可,表单中的 name 值对应着模型中的属性值,然后数据会被注入到一个自动构建的参数对象中。
form 表单

<form action="${basePath}pm/usecase/save" method="POST">
    <label for="num">Num</label> 
    <input type="text" id="Num" name="num"><br>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">label </span><span style="color: rgba(255, 0, 0, 1)">for</span><span style="color: rgba(0, 0, 255, 1)">="name"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>Name<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">label</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span> 
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">input </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="text"</span><span style="color: rgba(255, 0, 0, 1)"> id</span><span style="color: rgba(0, 0, 255, 1)">="name"</span><span style="color: rgba(255, 0, 0, 1)"> name</span><span style="color: rgba(0, 0, 255, 1)">="name"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;</span><span style="color: rgba(128, 0, 0, 1)">br</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">label </span><span style="color: rgba(255, 0, 0, 1)">for</span><span style="color: rgba(0, 0, 255, 1)">="description"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>Description<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">label</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">textarea </span><span style="color: rgba(255, 0, 0, 1)">rows</span><span style="color: rgba(0, 0, 255, 1)">="3"</span><span style="color: rgba(255, 0, 0, 1)"> name</span><span style="color: rgba(0, 0, 255, 1)">="description"</span><span style="color: rgba(255, 0, 0, 1)"> id</span><span style="color: rgba(0, 0, 255, 1)">="description"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">textarea</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;</span><span style="color: rgba(128, 0, 0, 1)">br</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">label </span><span style="color: rgba(255, 0, 0, 1)">for</span><span style="color: rgba(0, 0, 255, 1)">="status"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>Status<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">label</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span> 
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">select </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="form-control"</span><span style="color: rgba(255, 0, 0, 1)">
    id</span><span style="color: rgba(0, 0, 255, 1)">="status"</span><span style="color: rgba(255, 0, 0, 1)"> name</span><span style="color: rgba(0, 0, 255, 1)">="status"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">option </span><span style="color: rgba(255, 0, 0, 1)">value</span><span style="color: rgba(0, 0, 255, 1)">="1"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>创建<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">option</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">option </span><span style="color: rgba(255, 0, 0, 1)">value</span><span style="color: rgba(0, 0, 255, 1)">="2"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>完成<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">option</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">select</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;</span><span style="color: rgba(128, 0, 0, 1)">br</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">label </span><span style="color: rgba(255, 0, 0, 1)">for</span><span style="color: rgba(0, 0, 255, 1)">="author"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>Author<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">label</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span> 
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">input </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="text"</span><span style="color: rgba(255, 0, 0, 1)"> id</span><span style="color: rgba(0, 0, 255, 1)">="author"</span><span style="color: rgba(255, 0, 0, 1)"> name</span><span style="color: rgba(0, 0, 255, 1)">="author"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;</span><span style="color: rgba(128, 0, 0, 1)">br</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">label </span><span style="color: rgba(255, 0, 0, 1)">for</span><span style="color: rgba(0, 0, 255, 1)">="complitionDate"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>ComplitionDate<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">label</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">input </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="date"</span><span style="color: rgba(255, 0, 0, 1)"> id</span><span style="color: rgba(0, 0, 255, 1)">="complitionDate"</span><span style="color: rgba(255, 0, 0, 1)"> name</span><span style="color: rgba(0, 0, 255, 1)">="complitionDate"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">input </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="time"</span><span style="color: rgba(255, 0, 0, 1)"> id</span><span style="color: rgba(0, 0, 255, 1)">="complitionTime"</span><span style="color: rgba(255, 0, 0, 1)"> name</span><span style="color: rgba(0, 0, 255, 1)">="complitionTime"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;</span><span style="color: rgba(128, 0, 0, 1)">br</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">button </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="submit"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="btn btn-default"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>Save<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">button</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</form>

模型
注意这个模型中的属性名称与表单中的 name 属性是一一对应的,如此才能够将值自动注入到相应的属性中

public class UsecaseViewModel {
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> UsecaseViewModel() {
}

 
private String wid;
private String num;
private String name;
private String description;
private int status;
private String author;
private String complitionDate;
private String complitionTime;
private String createDate;
private String moduleWid;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> getter and setter methods    </span>

}

控制器方法
此处控制器的参数,直接使用这个模型类型,这告诉 SpringMVC 将相关的数据自动构造成这个类型的一个对象,然后注入到这个方法中

@RequestMapping(value = "/pm/usecase/save", method = RequestMethod.POST)
public String saveUsecase(UsecaseViewModel model) {usecaseBus.saveUsecase(model);
    return "redirect:/pm/usecase/list/" + model.getModuleWid();}

 

6、控制器返回视图


6.1、返回视图

在 SpringMVC 中,控制器中的方法并不直接返回视图的完整路径,而是返回一个视图的名称,然后根据在 Spring 中配置的视图解析器,结合视图名称确定真正的视图。

根据在 SpringMVC 的配置类中配置的视图解析器:

@Bean
public ViewResolver viewResolver() {
    InternalResourceViewResolver viewResolver = 
            new InternalResourceViewResolver();
    viewResolver.setPrefix("/views/");
    viewResolver.setSuffix(".jsp");
 
    return viewResolver;
}

上面配置的内容表示在控制器返回的视图名称加上前缀“/views/”,和后缀“.jsp”,然后到 WebContent 下寻找对应的文件。
因此对于下面的控制器中返回的视图名称:

@GetMapping("/welcome")
public String welcome() {
    return "welcome";

}

其实际对应的视图文件应该是在 WebContent 目录下的:/views/welcome.jsp


6.2、携带数据返回视图

上面的方式只是简单的返回一个视图,但在实际开发中通常需要将一些数据展示到视图中,那么如何将这些数据携带到视图中呢?
观察下面的方法,这个方法的返回值不再是一个字符串,而是一个 ModelAndView 类型,然后在这个方法中创建了一个 ModelAndView 对象,这个构造函数中接受的字符串,就是视图的名称,此外可以向这个对象中添加键值对,这些添加到 ModeAndView 中的键值对实际上会被添加到 Request 中,然后被转发给 JSP 页面,这样我们就可以使用 EL 表达式直接获取这些值了。

@RequestMapping(value = "/todo/detail/{wid}")
public ModelAndView todoDetail(@PathVariable String wid) {
    ModelAndView mv = new ModelAndView("todoDetail");
    TodoDetailViewModel detail = todoBus.getDetail(wid);
    mv.addObject("detail", detail);
    return mv;
}

在 JSP 页面,可以直接使用 EL 表达式获取,此外还可以使用 JSTL。

<c:forEach items="${detail.items}" var="item" varStatus="status">
    <tr>
        <td>${status.index+1}</td>
        <td>${item.content}</td>
        <td>${item.createDate}</td>
        <td><a class="btn btn-default btn-sm" href="###"
            role="button">删除</a></td>
    </tr>
</c:forEach>

 

7、控制器转跳


7.1、控制器之间跳转

使用“redirect:”前缀,后面跟上 @RequestMapping 中配置的路径,即可实现控制器之间的跳转

return "redirect:/pm/usecase/list/" + model.getModuleWid();

 

7.2、跳转到外部链接

如果需要跳转到外部链接,则需要给出完整的路径,当然“redirect:”前缀也不能丢掉

return "redirect:http://myhost.com/absolutepath"