7 Controller类的写法
7.1 继承Controller接口
- 在自己写的Conrtoller类中继承Controller接口,
- 实现接口方法,
- 返回填写好数据信息和页面信息的ModelAndView对象。
- 在去容器中注册bean,id要加"/"符号
相关的注解(一样的作用):
@Component 组件
@Service service层
@Controller controller层
@Repository dao层
这些注解表示该类会被Spring接管,被这个注解的类中的所有方法,如果返回值是String并且有具体页面可以跳转的,那么就会被视图解析器解析。
四个注解不能混用,对应的类要用对应的注解,否则解析找不到资源。
@Controller注解类型用于声明Spring的实例是一个控制器。
Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能够在应用程序中找到注解,需要在配置文件中声明组件扫描。
<!-- 自动扫描指定的包,包下所有注解类都交给IOC容器来管理 -->
<context:component-scan base-package="com.swrici.controller"/>
7.2 一个简单通过@Controller注解实现的程序。
- 开启注解扫描
<?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"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 自动扫描指定的包,包下所有注解类都交给IOC容器来管理 -->
<context:component-scan base-package="com.swrici.controller"/>
<!--<mvc:default-servlet-handler/>-->
<!--<mvc:annotation-driven />-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
- 增加一个MyController类,使用注解实现。
@Controller //@Controller注解的类会自动添加到Spring中的上下文中
public class MyController2 {
//映射访问路径 ,可作用于方法
@RequestMapping("/h2")
public String test1(Model model){
//SpringMVC会自动实例化一个Model对象用于向视图中传值。
model.addAttribute("msg","hello,My friend!");
//返回视图位置
return "hello";//WEB-INF/jsp/hello.jsp
}
}
- WEB-INF目录下有jsp文件夹下有hello.jsp页面。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
- 运行Tomcat测试。
- 运行结果。
如果再在Controller类中增添新的方法并且指向通过页面,并传递的值不同的话,我们可以发现,页面的结果是不一样的,得出结论就是视图是可以复用的,而控制器和视图之间是弱耦合关系。
7.3 @RequestMapping
- @RequestMapping注解用于映射url到控制器类或一个特定的处理程序方法,可以用于类或方法上,用于类上表示类的所有响应请求的方法都是以该父地址为父路径。
- @RequestMapping同时注解类和方法,如下
代码:
@Controller
@RequestMapping("/h2")
public class MyController3 {
@RequestMapping("/c3test1")
public String test1(Model model){
model.addAttribute("msg","MyController3.test1()");
return "hello";
}
}
例如:
8 RestFul风格
8.1 RestFul风格概念
RestFul风格就是一个资源定位和资源操作的风格,不是标准也不是协议,基于这个风格设计的软件可以更加简洁,更有层次感,更易于实现缓存机制。(url参数用斜线连接)
- 资源:互联网上所有的事物都可以抽象为资源。
- 资源操作:使用POST,GET,PUT,DELETE,使用不同方法对资源进行操作。
传统方式操作资源:
通过不同的参数实现不同的效果!方式单一,post和get.
- http://127.0.0.1/item/queryItem.action?id=1 查询GET
- http://127.0.0.1/item/saveItem.action?id=1 新增POST
- http://127.0.0.1/item/updateItem.action?id=1 修改POST
- http://127.0.0.1/item/deleteItem.action?id=1 删除GET或POST
使用RestFul风格操作资源:
可以通过不同的请求方式来实现不同的效果!如下,请求地址一样,但是功能可以不同。
- http://127.0.0.1/item/1 查询 ,GET
- http://127.0.0.1/item 新增,POST
- http://127.0.0.1/item 更新,PUT
- http://127.0.0.1/item/1 删除,DELETE
8.2 RestFul风格代码实例:
- 新建一个Controller类
@Controller
public class RestFulController {
//传统风格:http://localhost:8976/add?a=1&&b=3
//RestFul:http://localhost:8976/add/2/5
//映射访问路径 value映射访问路径,method确定访问方式
@RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.GET)
public String test1(@PathVariable int a,@PathVariable int b, Model model){
int res = a+b;
//SpringMVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg",res);
//返回视图位置
return "hello";
}
}
在SpringMVC中可以通过 @PathVariable 注解,绑定一个url中的变量,该变量可以在@RequestMapping中使用。当映射路径中使用了@PathVariable注解的变量时,传统风格的传参方式会找不到资源,并且如果不带参也找不到资源,参数类型不同也会找不到资源。
使用路径变量的好处(@PathVariable),
- 使路径更加简洁。
- 通过参数更加方便,框架会自动进行类型转换。
- 通过路径变量的类型可以约束访问参数,如果类型不一样,则访问不到对应的请求方法
传参方式
- 传参方式可以在@RequestMapping中调用method=RequestMapping.[DELETE]|[PUT]|[POST]|GET]等设置具体的传参方式。
- 传参方式也可以一开始就调用对应的注解进行设置。
例如:@GetMapping、@PostMapping、@PatchMapping等等,都是修改前面单词即可。
405–接受方法(传参方式)不对,目标资源不支持。
小黄鸭调试法:解释一遍自己的代码,会突然发现代码的问题在哪里。我也需要一只小黄鸭!
9 SpringMVC:结果跳转方式
9.1 ModelAndView
ModelAndView,最老的办法
设置ModelAndView对象,根据view的名称和视图解析器跳到指定的页面。
页面路径:{视图解析器前缀}+ViewName+{视图解析器后缀}
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
对应的Controller类
public class MyController implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一个模型视图对象
ModelAndView modelAndView = new ModelAndView();
//在对象中添加具体的K-V信息
modelAndView.addObject("msg","GGBoy");
//对象的ViewName设置
modelAndView.setViewName("hello");
return modelAndView;
}
}
9.2 ServletAPI
通过设置ServletAPI,不需要视图解析器
- 通过HttpServletResponse进行输出。
- 通过HttpServletResponse进行重定向。
- 通过HttpServletRequest实现转发。
@Controller
public class ModelTest1 {
//控制台打印SessionId,表示我们可以拿到request和response
@RequestMapping("/ModelTest1/test1()")
public String test1(HttpServletRequest request, HttpServletResponse response) {
HttpSession session = request.getSession();
System.out.println(session.getId());
return "hello";
}
//使用response输出,在前端打印出信息
@RequestMapping("/ModelTest1/test2()")
public void test2(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.getWriter().println("Hello,Spring BY Servlet API.");
}
//转发,使用Response跳转页面,
@RequestMapping("/ModelTest1/test3()")
public void test3(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.sendRedirect("/index.jsp");
}
//重定向,使用Request跳转页面,
@RequestMapping("/ModelTest1/test4()")
public void test4(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
request.setAttribute("msg","/ModelTest1/test4()");
request.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(request,response);
}
}
9.3 SpringMVC
9.3.1 SpringMVC无视图解析器,进行重定向和转发
@RequestMapping("m1/t5")
public String test5(Model model){
model.addAttribute("msg","我来负责证明你不用视图解析器进行结果跳转!");
//默认的return路径,url没有变,调用了转发的方式
return "/WEB-INF/jsp/hello.jsp";
}
@RequestMapping("m1/t6")
public String test6(Model model){
model.addAttribute("msg","我来负责证明你不用视图解析器进行结果跳转!");
//url没有变,调用了转发的方式
return "forward:/WEB-INF/jsp/hello.jsp";
}
@RequestMapping("m1/t7")
public String test7(Model model){
model.addAttribute("msg","我来负责证明你不用视图解析器进行结果跳转!");
//url改变,调用了重定向的方式
return "redirect:/index.jsp";
}
9.3.2 有视图解析器的时候
@RequestMapping("m1/t8")
public String test8(Model model){
//url改变,调用了重定向的方式
return "redirect:/index.jsp";
}
@RequestMapping("m1/t9")
public String test9(Model model){
model.addAttribute("msg","我来负责证明你用视图解析器进行结果跳转!");
//url不变,调用了转发的方式
return "hello";
}
10 接收请求参数和数据回显
10.1 接受请求参数
10.1.1 接收单个参数请求
//1.前端传递的是单个参数
@GetMapping("/t1")
public String test1(String name, Model model){
//1.接受前端参数
System.out.println("接受到前端参数");
//2.将返回结果传递给前端
model.addAttribute("msg","接受到前端参数为:"+name);
//3.视图跳转
return "hello";
}
访问Url:http://localhost:8080/user/t2?name=swrici
10.1.2设置接受请求参数的别名
在方法参数前面使用 @RequestParam(“别名”) 注解。
//1.前端传递的是单个参数
@GetMapping("/t1")
public String test1(@RequestParam("userName") String name, Model model){
//1.接受前端参数
System.out.println("接受到前端参数");
//2.将返回结果传递给前端
model.addAttribute("msg","接受到前端参数为:"+name);
//3.视图跳转
return "hello";
}
访问Url:http://localhost:8080/user/t2?userName=swrici
10.1.3 对象传参
//2.前端传递的是一个对象
/*
使用对象接收多个数据的时候
1.当数据名字和对象中的属性名一致的话,
则赋值给对象中的属性,如果匹配不到,
则对象属性为不赋值的默认值
*/
@GetMapping("/t2")
public String test2(User user){
System.out.println(user);
return "hello";
}
url:http://localhost:8976/user/t2?id=1&name=swrici&age=3
10.2 数据回显到前端
10.2.1 通过ModelAndView
//类实现Controller接口handleRequest()方法
//在该方法中通过返回ModelAndView对象来回显数据
public class MyController implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一个模型视图对象
ModelAndView modelAndView = new ModelAndView();
//设置模型中携带的数据
modelAndView.addObject("msg","GGBoy");
//设置视图的名字
modelAndView.setViewName("hello");
return modelAndView;
}
}
10.2.2 通过ModelMap
@GetMapping("/t3")
public String test3(ModelMap modelMap){
modelMap.addAttribute("msg","我是modelMap");
return "hello";
}
10.2.3 通过Model
@GetMapping("/t4")
public String test4(Model model){
model.addAttribute("msg","我是model");
return "hello";
}
10.3 Model、ModelMap和ModelAndView
Model:只有几个方法,只适合用来存储数据,简化了新手对Model对象的理解。
ModelMap:继承了LinkedMap,除了实现自身的一些方法之外还,继承LinkedMap的方法和特性。
ModelAndView:可以在存储数据的同时,进行设置返回的逻辑视图。进行控制展示层的跳转。
11 乱码问题解决方案
11.1 自编过滤器解决乱码
- 编写过滤器类
public class EnCodingFilter implements 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>encoding</filter-name>
<filter-class>com.swrici.filter.EnCodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
这种自己编写过滤器的方法可以解决Get方式传参带来的影响,但无法解决Post方法乱码的影响。
11.2 SpringMVC自带的过滤器
<!--2.配置SpringMVC的乱码过滤器-->
<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>
通过web.xml中配置SpringMVC过滤器就可以解决大部分的情况下的get和post请求乱码情况。