吐血整理!14个编写Spring MVC控制器的实用小技巧

640?wx_fmt=jpeg

全文共4248字,预计学习时长9分钟

640?wx_fmt=png
编写Spring MVC控制器的最佳技巧

本文介绍了编写Spring MVC框架的控制器(controller)的基础技巧和最佳操作。 在Spring MVC框架中,编写控制器类通常是为了处理用户提出的请求。
 
编写完成后,控制器会调用一个业务类来处理业务相关任务,进而重定向客户到逻辑视图名。 Springdispatcher servlet会对逻辑视图名进行解析,并渲染结果或输出。 这就是一个典型的“请求—响应”的完整流程。
 

1.使用@controllerstereotype

 
创建一个能够处理单个或多个请求的控制器类,最简单的方法就是使用@controllerstereotype注解一个类,如:
 
import org.springframework.stereotype.Controller;	
import org.springframework.web.bind.annotation.RequestMapping;	
@Controller	
publicclassHomeController {	
    @RequestMapping("/")	
    publicString visitHome() {	
        // do something before returning view name	
        return"home";	
    }	
}

如上所示,visitHome()方法通过重定向跳转到视图名home来处理应用程序内容路径(/)收到的请求。
 
注意: 只有在Spring配置文件中启用了注解驱动,才能使用@controllerstereotype。
 
 
启用注解驱动后,Spring的容器(container)会自动扫描如下包中的类:
 
 
带有@controller注解的类会被标记成控制器。 由于其简单方便,且不再需要对配置文件中的控制器声明beans,这一方法非常实用。
 
注意: 使用@controller注解可以创建一个多动作控制器类,可同时处理多个不同的请求。 如:
 
@Controller	
publicclassMultiActionController {	
    @RequestMapping("/listUsers")	
    public ModelAndView listUsers() {	
    }	
    @RequestMapping("/saveUser")	
    public ModelAndView saveUser(User user) {	
    }	
    @RequestMapping("/deleteUser")	
    public ModelAndView deleteUser(User user) {	
    }	
}

如上所示,有三个处理器(handler)在分别处理三个请求,/listUsers,/saveUser,和/deleteUser。
 

2.实现控制器接口

 
在Spring MVC中创建控制器还可以用另一个经典的方法,即对一个类实现Controller接口。 如:
 
import javax.servlet.http.HttpServletRequest;	
import javax.servlet.http.HttpServletResponse;	
import org.springframework.web.servlet.ModelAndView;	
import org.springframework.web.servlet.mvc.Controller;	
publicclassMainControllerimplements Controller {	
    @Override	
    public ModelAndView handleRequest(HttpServletRequest request,	
            HttpServletResponse response) throws Exception {	
        System.out.println("Welcome main");	
        returnnew ModelAndView("main");	
    }	
}

实现类必须重写handleRequest()方法(当收到相匹配的请求时,Spring dispatcher servlet会调用handleRequest)。 由该控制器处理的请求URL模式在Spring的内容配置文件中的定义如下:
 
 
这一方法的缺点在于其控制类无法同时处理多个请求URL。
 

3.继承AbstractController类

 
如果想要轻松控制受支持的HTTP方法、会话和内容缓存,让控制类继承AbstractController类是理想的方法。 如:  
 
import javax.servlet.http.HttpServletRequest;	
import javax.servlet.http.HttpServletResponse;	
import org.springframework.web.servlet.ModelAndView;	
import org.springframework.web.servlet.mvc.AbstractController;	
publicclassBigControllerextends AbstractController {	
    @Override	
    protected ModelAndView handleRequestInternal(HttpServletRequest request,	
            HttpServletResponse response) throws Exception {	
        System.out.println("You're big!");	
        returnnew ModelAndView("big");	
    }	
}
 
上例创建了一个配置了受支持的方法、会话和缓存的单动作控制器,能够在控制器的bean声明中被指明。 如:
 
<beanname="/big"class="net.codejava.spring.BigController">	
    <propertyname="supportedMethods"value="POST"/>	
</bean>
 
这一配置表明该控制器handler方法仅支持POST方法。 了解更多配置(如会话、缓存),参见 AbstractController 。  
 
SpringMVC还提供了多个支持特定目的的控制器类,包括:
 
  • AbstractUrlViewController
  • MultiActionController
  • ParameterizableViewController
  • ServletForwardingController
  • ServletWrappingController
  • UrlFilenameViewController
 

4.为处理器指定URL映射

 
这是编写控制器类必不可少的一步,旨在处理一个及以上特定请求。 Spring MVC提供了@RequestMapping注解,用于指定URL映射。 如:
 
 
这一步映射了URL模式/login,并用注解或注解类对其进行了处理。 @RequestMapping注解用于类上时,类变成了单动作控制器。 如:
 
import org.springframework.stereotype.Controller;	
import org.springframework.web.bind.annotation.RequestMapping;	
import org.springframework.web.bind.annotation.RequestMethod;	
@Controller	
@RequestMapping("/hello")	
publicclassSingleActionController {	
    @RequestMapping(method = RequestMethod.GET)	
    publicString sayHello() {	
        return"hello";	
    }	
}
 
@RequestMapping注解用于方法上时,则可生成多动作控制器。 如:  
 
import org.springframework.stereotype.Controller;	
import org.springframework.web.bind.annotation.RequestMapping;	
@Controller	
publicclassUserController {	
    @RequestMapping("/listUsers")	
    publicString listUsers() {	
        return"ListUsers";	
    }	
    @RequestMapping("/saveUser")	
    publicString saveUser() {	
        return"EditUser";	
    }	
    @RequestMapping("/deleteUser")	
    publicString deleteUser() {	
        return"DeleteUser";	
    }	
}
 
@RequestMapping注解也可用于指定多个URL模式,并用单一方法对其进行处理。 如:
 
 
此外,该注解还有其他的属性,在一些情况下能发挥作用,如下一小节将讲到的method属性。
 

5.为处理器方法指定HTTP请求方法

 
使用@RequestMapping注解的method属性,可以指定处理器方法支持的HTTP方法(包括GET、POST、PUT等)。 如:
 
import org.springframework.stereotype.Controller;	
import org.springframework.web.bind.annotation.RequestMapping	
import org.springframework.web.bind.annotation.RequestMethod;	
@Controller	
publicclassLoginController {	
    @RequestMapping(value = "/login", method = RequestMethod.GET)	
    publicString viewLogin() {	
        return"LoginForm";	
    }	
    @RequestMapping(value = "/login", method = RequestMethod.POST)	
    publicString doLogin() {	
        return"Home";	
    }	
}
 
如上所示,对于同一个URL模式/login,该控制器有两个处理方法。 第一个方法用于GET方法,第二个则用于POST方法。
 
了解更多@RequestMapping注解相关知识,参见 @RequestMapping注解 。  


6.将请求参数映射至处理器方法

 
SpringMVC的特征之一,就是可以使用@RequestParam注解将请求参数作为处理器方法的常规参数取回。 这是一个将控制器从ServletAPI的HttpServletRequest接口中解耦出来的好方法。  
 
如:
 
@RequestMapping(value = "/login", method = RequestMethod.POSTpublic String doLogin(@RequestParamString username @RequestParamString password) {}
 
Spring将方法参数用户名及密码和命名相同的HTTP请求参数绑定到一起。 这也就意味着可用如下方式调用一个URL(以GET请求方法为例):
 
http://localhost:8080/spring/login?username=scott&password=tiger
 
类型转换也自动完成了。 如果对一个integer类型的参数声明如下:
 
 
则Spring会在处理方法中自动将请求参数的值(String类型)转换为指定类型(integer)。
 
为防止参数名与变量名不同,可将参数实名指定如下:
 
 
@RequestParam注解还有另外两个属性,可在一些情况下发挥作用。 其中一个属性是required,可指定一个参数是强制参数还是可选参数。 如:
 
 
这就意味着参数country是可选的,在请求中可略去。 当请求中没有参数country时,则变量country为空值。  
 
另一个属性是defaultValue,可在请求参数为空时充当回退值(fallbackvalue)。 如:
 
 
当方法参数类型为Map<String,String>时,Spring也支持将所有参数作为Map对象。 如:
 
 
则映射参数包含所有键值对形式的请求参数。 了解更多@RequestParam注解相关知识,参见 @RequestParam 注解。  
 

7.返回模型和视图

 
处理器方法在处理完业务逻辑后,会返回一个视图,该视图随后由Springdispatcher servlet进行解析。 Spring支持handler方法返回String对象或ModelAndView对象。 如下所示,handler方法返回了一个String对象,并表示了视图名LoginForm:
 
@RequestMapping(value = "/login", method = RequestMethod.GET)	
public String viewLogin() {	
    return"LoginForm";	
}
 
这是返回视图名最简单的方法。 但是如果想要发送其他数据到视图,则必须返回ModelAndView对象。 如:  
 
@RequestMapping("/listUsers")	
public ModelAndView listUsers() {	
    List<User> listUser = new ArrayList<>();	
    // get user list from DAO...	
    ModelAndView modelView = new ModelAndView("UserList");	
    modelView.addObject("listUser", listUser);	
    return modelView;	
}

如上所示,该处理器方法返回了一个ModelAndView对象,该对象视图名为UserList,并有一个可用在视图中的User对象集。
 
Spring是一个非常灵活的框架,支持将ModelAndView对象声明为处理器方法的参数,而无需再重新创建一个。 因此,上例可以重写为:
 
@RequestMapping("/listUsers")	
public ModelAndView listUsers(ModelAndView modelView) {	
    List<User> listUser = new ArrayList<>();	
    // get user list from DAO...	
    modelView.setViewName("UserList");	
    modelView.addObject("listUser", listUser);	
    return modelView;	
}
 
了解更多ModelAndView类相关知识,参见 ModelAndView类 。  
 

8.将对象放入模型

 
在MVC架构的应用程序中,控制器将数据输入到模型中,该模型则被用在视图中。 从上一节中的举例中可以看到,ModelAndView类的addObject()用于将对象以名值对的形式放入模型中:
 
modelView.addObject("listUser", listUser);	
modelView.addObject("siteName", newString("CodeJava.net"));	
modelView.addObject("users", 1200000);
 
Spring同样支持声明处理器方法中的Map类型参数。 Spring使用这一映射存储将放入模型的对象。 如:
 
@RequestMapping(method = RequestMethod.GET)	
publicStringviewStats(Map<String, Object> model) {	
    model.put("siteName", "CodeJava.net");	
    model.put("pageviews", 320000);	
    return"Stats";	
}
 
这一方法比使用ModelAndView对象更加简单。 Spring支持用户灵活选择Map对象和ModelAndView对象。
 

9.处理器方法中的重定向

 
当条件允许时,只需在URL前加上redirect:/就可将用户重定向跳转到另一个URL。 如:
 
// check login status....	
if (!isLogin) {	
    returnnew ModelAndView("redirect:/login");	
}	
// return a list of Users
 
在上述代码中,没有登陆的用户将会跳转到/loginURL。
 

10.处理表单提交和表单验证

 
Spring中的@ModelAttribute注解支持将表单字段绑定到表单返回对象,BingingRequest接口则支持验证表单字段。 这使得处理表单提交变得非常简单。 一个处理和验证表单数据的典型处理器方法的代码如下所示:
 
@Controller	
publicclassRegistrationController {	
    @RequestMapping(value = "/doRegister", method = RequestMethod.POST)	
    publicString doRegister(	
        @ModelAttribute("userForm") User user, BindingResult bindingResult) {	
        if (bindingResult.hasErrors()) {	
            // form validation error	
        } else {	
            // form input is OK	
        }	
        // process registration...	
        return"Success";	
    }	
}
 
了解更多@ModelAttribute注解和BindingResult接口相关知识,参见Spring官方文档:
 
  • Using @ModelAttribute on a method argument
  • Using @ModelAttribute on a method
  • Interface BindingResult
 

11.处理文件上传

 
Spring支持自动将上传数据绑定到CommonsMultiparFile数组对象,这使得在处理器方法中处理文件上传变得非常简单。 Spring使用 Apache CommonsFileUpload 作为深层多部分解析器(underlyingmultipart resolver)。
 
简单上传用户文件的代码如下所示:
 
@RequestMapping(value = "/uploadFiles", method = RequestMethod.POST)	
publicStringhandleFileUpload(	
        @RequestParam CommonsMultipartFile[] fileUpload) throws Exception {	
    for (CommonsMultipartFile aFile : fileUpload){	
        // stores the uploaded file	
        aFile.transferTo(new File(aFile.getOriginalFilename()));	
    }	
    return"Success";	
}
 
了解Spring MVC处理文件上传的完整方法,参见 Spring MVC 文件上传教程 。  
 

12.在处理器中自动注入业务类

 
为了让控制器将业务逻辑处理委托到相关业务类,可以使用@Autowired注解,让Spring自动将业务类的实际实现注入到控制器中。 如:
 
@Controller	
publicclassUserController {	
    @Autowired	
    private UserDAO userDAO;	
    publicString listUser() {	
        // handler method to list all users	
        userDAO.list();	
    }	
    publicString saveUser(User user) {	
        // handler method to save/update a user	
        userDAO.save(user);	
    }	
    publicString deleteUser(User user) {	
        // handler method to delete a user	
        userDAO.delete(user);	
    }	
    publicString getUser(int userId) {	
        // handler method to get a user	
        userDAO.get(userId);	
    }	
}
 
本例中所有与用户管理相关的业务逻辑都由UserDAO接口的实现提供。 如:

interfaceUserDAO {	
    List<User> list();	
    void save(User user);	
    void checkLogin(User user);	
}
 
如上所示,使用@Autowired注解使处理器方法可以将任务委托到业务类:
 
 
了解更多@Autowired注解相关知识,参见 Annotation TypeAutowired 。
 

13.获取HttpServletRequest和HttpServletResponse

 
有些情况要求在处理器方法中直接获取HttpServletRequest或HttpServletResponse对象。 在Spring灵活的框架中,仅需给处理器方法加上一个相关参数就可以完成此任务。 如:
 
@RequestMapping("/download")	
publicStringdoDownloadFile(	
        HttpServletRequest request, HttpServletResponse response) {	
    // access the request	
    // access the response	
    return"DownloadPage";	
}
 
Spring支持检测并自动将HttpServletRequest和HttpServletResponse对象注入到方法中。 这样一来,就可以直接获取请求和响应,如获取InputStream、OutputStream或返回特定的HTTP代码。
 

14.遵守单一职责原则

 
在Spring MVC中设计和编写控制器时,应遵循以下两个非常实用的操作:
 
  • 不要用控制器类来执行业务逻辑,应该用控制器类将业务处理委托到相关的业务类。 这可以保证控制器专注于其指定职责,即控制应用程序的工作流。 如:
 
@Controller	
publicclassUserController {	
    @Autowired	
    private UserDAO userDAO;	
    publicString listUser() {	
        // handler method to list all users	
        userDAO.list();	
    }	
    publicString saveUser(User user) {	
        // handler method to save/update a user	
        userDAO.save(user);	
    }	
    publicString deleteUser(User user) {	
        // handler method to delete a user	
        userDAO.delete(user);	
    }	
    publicString getUser(int userId) {	
        // handler method to get a user	
        userDAO.get(userId);	
    }	
}
 
  • 给每个业务领域创建一个独立的控制器。 如,用UserController控制用户管理的工作流,用OrderController控制订单处理的工作流,等等:
 
@Controller	
publicclassUserController {	
}	
@Controller	
publicclassProductController {	
}	
@Controller	
publicclassOrderController {	
}	
@Controller	
publicclassPaymentController {	
}
 
以上就是本文全部内容,希望这14个小技巧可以帮助读者准确且高效地编写Spring MVC中的控制器类代码。 有任何技巧分享或建议,欢迎在评论区留言。
 
640?wx_fmt=png
推荐阅读专题


640?wx_fmt=jpeg
留言 点赞 发个朋友圈
我们一起分享AI学习与发展的干货

编译组: 王努铱、莫菲菲
相关链接:
https://dzone.com/articles/14-tips-for-writing-spring-mvc-controller

如需转载,请后台留言,遵守转载规范

推荐文章阅读

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值