文章目录
SpringMVC基础(二)
使用注解开发SpringMVC
@Controller
@RequestMapping
-
配置web.xml(与使用配置文件开发中一直)
-
配置springmvc-servlet.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 自动扫描包,使得包中的注解生效 --> <context:component-scan base-package="com.qiu.controller"/> <!-- 使SpringMVC不处理静态资源,例如:.css .js .html .mp3。过滤这些资源,也就是使用url访问这些资源的时候不会被DispatcherServlet捕获 --> <mvc:default-servlet-handler/> <!-- 原来需要配置处理映射器、适配器,现在只需要一个注解驱动即可;写上这个spring就会自动帮我们开启两个器,并且自动注入到spring容器中 --> <mvc:annotation-driven/> <!--视图解析器:DispatcherServlet给他的ModelAndView--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean> <!-- 不需要写请求控制器连接的handler了,在注解中写 --> </beans>
扫描到包后,包中的注解会生效。遇到@Controller注解时,会自动将控制器注册到spring容器中。@RequestMapping("/hello")就是那个映射请求与Controller的bean,自动注入进入!
-
写Controller
// 声明HelloSpringMvc是一个Controller,而不用implements了 @Controller public class HelloSpringMvc { // 请求与Controller映射,相当于原来那个请求控制器连接bean;这也是将这个方法作为请求控制器连接bean注册到spring容器中 // 每一个@RequestMapping就对应一个handlerBean @RequestMapping("/hello") public String hello(Model model){ // 封装数据使用model进行封装,在跳转的时候model跟着一起转发 model.addAttribute("msg", "HelloSpringMVC"); // 这个return会被视图解析器处理,自动跳转到视图;与原来使用mv是相同的。 return "hello"; } @RequestMapping("/hello2") public String hello(Model model){ model.addAttribute("msg", "HelloSpringMVC"); return "hello2"; } @RequestMapping("/hello3") public String hello(Model model){ model.addAttribute("msg", "HelloSpringMVC"); return "hello"; } }
原来一个业务需要多种情况的时候,需要每个情况对应一个页面一个Controller(每个Controller中只有一个handler)。但是使用这种方法可以将同种业务的handler放在一起,一个Controller中。
增加层级访问路径
@RequestMapping
// 声明HelloSpringMvc是一个Controller,而不用implements了
@Controller
@RequestMapping("/hello")
public class HelloSpringMvc {
@RequestMapping("/h1")
public String hello(Model model){
model.addAttribute("msg", "HelloSpringMVC");
return "hello";
}
}
@RequestMapping可以在方法上写,也可以在类上写。类上写就表明这是一个父路径,在方法上写就表明这是一个子路径。
也就是说,现在访问hello方法(handler),需要url写成:xxx/hello/h1。才能访问到这个handler
从servlet容器中先找到Controller(/hello),在从Controller中找到对应的handler(/h1)。原来因为一个Controller中只有一个handler所以不需要写第二路径,直接访问Controller就可以使用handler,现在多了一个需要先到父路径在到handler。
定义访问方式权限,确保安全性
@RequestMapping可以修改访问handler的方式(POST、DELETE、PUT、GET)。
如果说不想让用户访问登录的handler(登录的handler需要用户名密码参数)
@Controller
@RequestMapping("/hello")
public class HelloSpringMvc {
@RequestMapping("/h1", method=RequestMethod.POST)
public String hello(String id, String password, Model model){
model.addAttribute("msg", "HelloSpringMVC"+c);
return "hello";
}
}
这样使用这种uri就不能访问了:
http://localhost:8080/hello/h1?id=123&password=123456
因为这样的uri是GET方式的,而我们限制的handler需要是POST方式才可以访问!
注意:POST方式可以带参数,但是POST方式uri中不能携带参数,只能通过表单发送。因为POST方式的参数是隐藏的。
RestFul风格
以前在url中携带参数使用?参数=xxx寻找资源,使用RestFul风格后使用 /资源 即可找到资源。
RestFul就是一个资源定位以及资源操作的风格,不是一种协议、标准,仅仅只是一种风格!
作用:RestFul的最大的作用是安全,因为你不能知道那个参数的含义是什么!
功能:
-
资源:互联网所有的事务都可以被抽象为资源
-
资源操作:使用POST、DELETE、PUT、GET,使用不同的方法对资源进行操作。
分别对应: 添加、删除、修改、查询
@PathVariable
在SpringMVC中使用 @PathVariable 注解,让方法参数的值对应绑定到URI模板变量上。
例如:
@Controller
@RequestMapping("/hello")
public class HelloSpringMvc {
// 在请求上改动,使得uri可以是这种风格的
@RequestMapping("/h2/{a}/{b}")
public String sayHello(@PathVariable int a,@PathVariable int b, Model model){
int c = a + b;
model.addAttribute("msg", "HelloSpringMVC"+c);
return "hello2";
}
}
这样可以这样使用:
uri = http://localhost:8080/hello/h2/1/2
结果为:HelloSpringMVC3
传统的uri = http://localhost:8080/hello/h2?a=1&b=2
这样使用就可以切换风格了。原来是链接式风格、现在是请求式风格。
注意!使用这种风格需要两点:
- 修改请求映射
- 添加注解 @PathVariable
接受请求 与 请求转发与重定向
接收请求
DispatcherServlet中有一个方法是doService,请求到DispatcherServlet中先去找doService,在从doService中判断寻找请求要找的handler!
所以我们写的handler可以有HttpServletRequest、HttpServletResponse!(你只要写上这个参数这是可以接收的)
@Controller
@RequestMapping("/hello")
public class HelloSpringMvc {
@RequestMapping("/h3")
public void test(HttpServletRequest req, HttpServletResponse rsp){
String name = req.getParameter("name");
int age = (Integer) req.getAttribute("age");
try {
req.getRequestDispatcher("/index.jsp").forward(req, rsp);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意一点,这种请求转发并不太好,你可以使用之前跳转视图的方法return进行转发(在Model中携带数据)。
请求转发与重定向
请求转发(可访问WEB-INF)
@Controller
@RequestMapping("/hello")
public class HelloSpringMvc {
@RequestMapping("/h3")
public String test(HttpServletRequest req, HttpServletResponse rsp){
return "hello";
}
}
这种直接文件名的方式是请求转发的方式,注意要String!
重定向(不可访问WEB-INF)
@Controller
@RequestMapping("/hello")
public class HelloSpringMvc {
@RequestMapping("/h3")
public String test(HttpServletRequest req, HttpServletResponse rsp){
return "redirect:/index.jsp";
}
}
注意!这里是要加jsp后缀的,并且重定向不能访问WEB-INF下的文件!
因为WEB-INF下的文件只能由服务端级别才能访问,客户端级别访问不了!,而重定向发生了两次请求第二次请求是真正请求的(由客户端发出请求)所以重定向访问不了WEB-INF下的文件!
Handler接收Param参数
如果你喜欢用 RestFull风格、或者使用request 接收参数的话就不用看下面的了,这里的接收参数是对于url栏中参数而言的
最好还是用request接收一下呗,又不费劲
直接接收参数Param
@Controller
@RequestMapping("/hello")
public class HelloSpringMvc {
@RequestMapping("/h1")
public String test(String name){
System.out.println(name);
return "redirect:/index.jsp";
}
}
这样直接使用url:http://localhost:8080/hello/h1?name=xxx 就可以访问
URL栏参数名与handler中参数名不一致
如果url中的域名的携带参数与handler中的参数不一致,可以使用名称映射注解。
@Controller
@RequestMapping("/hello")
public class HelloSpringMvc {
@RequestMapping("/h1")
public String test(@RequestParam("username") String name){
System.out.println(name);
return "redirect:/index.jsp";
}
}
这样url可以这样写:http://localhost:8080/hello/h1?username=xxx
接收一个对象
直接将参数封装成一个对象,使用对象作为参数即可
class User{
private int age;
private String name;
}
@Controller
@RequestMapping("/hello")
public class HelloSpringMvc {
@RequestMapping("/h1")
public String test(User user){
System.out.println(user.toString());
return "redirect:/index.jsp";
}
}
这样url可以这样写:http://localhost:8080/hello/h1?id=1&name=xxx
传递参数给前端
- 就直接使用model传递参数给前端!
- 就直接使用ModelAndView传递参数给前端!
- 使用注解@ResponseBody屏蔽视图解析器,并将return值放在response中返回给前端
- 使用ModelMap传递参数给前端
ModelMap是Model的一个父类,它继承自LinkedHashMap(拥有LinkedHashMap的全部方法)。Model是ModelMap的精简版本,大部分情况用Model就够了!
前两种一样的用法,return都是经过视图解析器的
屏蔽handler的视图解析器return数据给前端(@ResponseBody)
用法:在handler上用==@ResponseBody==屏蔽该handler的视图解析器作用。
那么return的值就不会经过视图解析器解析,而是将return值放在response中return给前端。
@Controller
@RequestMapping("book")
public class BookController {
@Autowired
@Qualifier("bookServiceImpl")
private BookService bookService;
@RequestMapping("/allBook")
public String queryList(Model model){
List<Books> list = bookService.queryAllBook();
model.addAttribute("allBooks", list);
return "allBook";
}
@ResponseBody
@RequestMapping("/test")
public String test(){
return "allBook";
}
}
这样访问 /book/test 就是向response域中添加字符串 allBook 而不是转发到 allBook.jsp
但是访问 book/allBook 仍会经过视图解析器然后转发!
注意 @ResponseBody 屏蔽掉的是一个handler的视图解析器,而不是整个Controller的视图解析器,所以没写注解的handler仍可以经过视图解析器!
屏蔽整个Controller的视图解析器return数据给前端(@RestController)
使用 @RestController = @Controller + @ResponseBody
@RestController
@RequestMapping("book")
public class BookController {
@Autowired
@Qualifier("bookServiceImpl")
private BookService bookService;
@RequestMapping("/allBook")
public String queryList(Model model){
List<Books> list = bookService.queryAllBook();
model.addAttribute("allBooks", list);
return "allBook";
}
@RequestMapping("/test")
public String test(){
return "allBook";
}
}
或者使用 @ResponseBody + @Controller
@Controller
@ResponseBody
@RequestMapping("book")
public class BookController {
@Autowired
@Qualifier("bookServiceImpl")
private BookService bookService;
@RequestMapping("/allBook")
public String queryList(Model model){
List<Books> list = bookService.queryAllBook();
model.addAttribute("allBooks", list);
return "allBook";
}
@RequestMapping("/test")
public String test(){
return "allBook";
}
}
解决乱码问题
原始方法
在原来纯servlet中乱码可以使用request的setCharacterEncoding解决。但是在Spring中已经不知道封装了多少次了,在封装中就已经乱码了。所以我们在handler中使用request来解决乱码是不可以的!
这样我们只能必须配置一个过滤器来解决乱码了!!!
public class Filter implements javax.servlet.Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest, servletResponse);
}
public void destroy() {
}
}
在web.xml中配置一下过滤器
<filter>
<filter-name>filter</filter-name>
<filter-class>com.qiu.filter.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
*注意这里必须要是“/*”,只有“/ ”才能拦截jsp。
SpringMVCfangfa
SpringMVC为我们提供了过滤器,直接在web.xml中使用就行了!
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
不需要我们手动写Filter了。