2g SpringMVC基础.txt

UP 返回
1 简介
	MVC	M:Model	V:View		C:Controller - servlet/action/controller
	Spring MVC是Spring提供的一个强大而灵活的web框架。借助于注解,Spring MVC提供了几乎是POJO的开发模式,使得控制器的开发和测试更加简单。这些控制器一般不直接处理请求,而是将其委托给Spring上下文中的其他bean,通过Spring的依赖注入功能,这些bean被注入到控制器中。
	Spring MVC主要由DispatcherServlet、处理器映射【找控制器】、适配器【调用控制器的方法】、控制器【业务】、视图解析器、视图组成。

2.创建项目		█参见项目:D:\ProjectCodes\IDEA2017\springmvc-test1
   2.1 导入springmvc jar包
	创建工程同06
	除了以前的jar,需要额外加入spring-webmvc的jar
   2.2 在web.xml配置DispatcherServlet(WEB-INF目录下)
	★web.xml代码
	<?xml version="1.0" encoding="UTF-8"?>
	<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	         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_3_1.xsd"
	         version="3.1">
	
	    <!--▶配置:所有的请求由SpringMVC管理-->
	    <servlet>
	        <servlet-name>DispatcherServlet</servlet-name>
	        <!--▶所有请求转发给DispatcherServlet-->
	        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	        <load-on-startup>1</load-on-startup>
	    </servlet>
	
	    <servlet-mapping>
	        <servlet-name>DispatcherServlet</servlet-name>
	        <url-pattern>*.do</url-pattern>
	    </servlet-mapping>
	
	</web-app>
   2.3 在WEB-INF目录下创建DispatcherServlet-servlet.xml(名字和位置默认是这个)
	★DispatcherServlet-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" xmlns:mvc="http://www.springframework.org/schema/mvc"
	       xmlns:context="http://www.springframework.org/schema/context"
	       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	       xsi:schemaLocation="http://www.springframework.org/schema/beans
			http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
			http://www.springframework.org/schema/mvc
			http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
			http://www.springframework.org/schema/context
			http://www.springframework.org/schema/context/spring-context-3.2.xsd
			http://www.springframework.org/schema/aop
			http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
			http://www.springframework.org/schema/tx
			http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
	
	    <!--▶1.配置url处理映射-->
	    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
	
	    <!--▶2.配置控制器处理适配器-->
	    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
	
	    <!--▶3.配置控制器-相当于配置了访问路径-->
    	    <bean name="/user.do" class="com.dm.backoffice.web.controller.UserController"></bean>
	
	    <!--▶4.配置资源视图解析器-->
	    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	        <!--前缀和后缀,方便查找jsp(会自动加在controller中写的页面前后拼接)-->
	        <property name="prefix" value="/WEB-INF/views/"></property>
	        <property name="suffix" value=".jsp"></property>
	    </bean>
	
	</beans>
   2.4 配置DispatcherServlet-servlet.xml
	参2.3中内容
   2.5 创建个Controller控制器
	public class UserController implements Controller {	//▶注意导包时不要导错了,选org.springframework.web.servlet.mvc.Controller;
	
	    @Override
	    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
	        ModelAndView mav=new ModelAndView("user/userlist");	//▶会和DispatcherServlet-servlet.xml中配置的前后缀相结合
	        mav.addObject("name","haha");
	        return mav;
	    }
	}
   2.6 创建一个userList.jsp页面
	<%@ page contentType="text/html;charset=UTF-8" language="java" %>
	<html>
	<head>
	    <title>用户列表</title>			
	</head>
	<body>
	${name}:<br>		▶取出后台返回的name值
	</body>
	</html>
   2.7运行项目,访问路径
	浏览器输入:http://localhost:8080/user.do,运行

3.运行流程
	首先浏览器发出请求,根据web.xml中的配置,该请求会交给DispatcherServlet处理
	他再根据DispatcherServlet-servlet.xml的配置,将请求交给url处理映射BeanNameUrlHandlerMapping。该类会根据url的名字比对bean的name属性来寻找对应的controller,然后由SimpleControllerHandlerAdapter来执行对应的控制层,并返回页面模型modelandview
	最后InternalResourceViewResolver会依据配置的前后缀查找jsp路径,响应页面

4.详解DispatcherServlet-servlet.xml属性
   4.1 配置URL处理映射的方式有三种(▶了解即可,因为以后都是用注解来配)
	BeanNameUrlHandlerMapping:通过url名字,找到对应的bean的name的控制器。如上述DispatcherServlet-servlet.xml中所示
		<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
    		<bean name="/user.do" class="com.dm.backoffice.web.controller.UserController"></bean>
	SimpleUrlHandlerMapping:通过key找到bean的id的控制器
		<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	        <property name="mappings">
	            <props>
	                <prop key="/user1.do">userController</prop>		▶这三个url都会指向下面的userController控制器
	                <prop key="/user2.do">userController</prop>
	                <prop key="/user3.do">userController</prop>
	            </props>
	        </property>
	    </bean>
	    <bean id="userController" class="com.dm.backoffice.web.controller.UserController"></bean>
	ControllerClassNameHandlerMapping:不用配置访问路径,默认的访问路径就是类名(首字母变小写,后面加.do。具体的访问方式有区别,参视频,但是没必要去了解了)
	    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"></bean>
	    <bean class="com.dm.backoffice.web.controller.UserController"></bean>		▶访问userController.do即可
   4.2 配置控制器处理适配器:配置如何调用控制器的方法
	SimpleControllerHandlerAdapter	执行controller,调用controller里面方法,返回modelAndView
	    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
		▶该方式对应的控制层需要实现Controller,此方法返回一个ModelAndView,返回的页面可以直接设置好
	HttpRequestHandlerAdapter			执行控制器,负责调用实现HttpRequestHandler接口的控制器
	    <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
		▶该方法对应的控制层需要实现HttpRequestHandler,此方法返回null,故需要自己写返回的页面路径:
			public class HttpController implements HttpRequestHandler {
			    @Override
			    public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
			        request.setAttribute("name","haha");
			        request.getRequestDispatcher("/WEB-INF/views/user/userlist.jsp").forward(request,response);	//▶转发
			    }
			}
   4.3 命令控制器(演示的类过时了,spring4.2引用不了,代码无法跑起来,项目中没写代码。了解即可,相当于是底层实现)
	■添加页面useradd.jsp
	<form action="${pageContext.request.contextPath}/command.do" method="post">
	    用户名:<input type="text" name="username"><br>
	    密码:<input type="text" name="password"><br>
	    性别:<input type="text" name="gender"><br>
	    生日:<input type="text" name="birthday"><br>
	    <input type="submit">
	</form>
	■Command控制器
	public class UserAddController implements Controller {
	    @Override
	    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
	        ModelAndView mav=new ModelAndView("user/useradd");
	        return mav;
	    }
	}
	
	public class CommandController extends AbstractCommandController{		//继承的这个父类找不到了
		//▶指定哪个bean来接收参数
		public CommandController(){
			this.setCommandClass(User.class);
		}
		@Override
		protected ModelAndView handle(HttpServletRequest requset,HttpServletResponse response,Object command,BindException errors) throws Exception{
			//转成用户对象
			User user =(User) command;
			ModelAndView mv=new ModelAndView();
			//添加数据
			mv.addObject("user",user);
			//返回页面
			mv.setViewName("/user/info");
			return mv;
		}
	}
	■info.jsp
	<body>
	<!-- 从控制器中取数据 -->
	${user.username} || ${user.password}
	</body>
	★DispatchServelt-sevlet配置文件
	<bean name="/useradd.do" class="com.dm.backoffice.web.controller.UserAddController"></bean>		▶注意name中要加/
	<bean name="/command.do" class="com.dm.backoffice.web.controller.CommandController"></bean>
	★views结构
	views\user下有两个页面,首先访问useradd.jsp,填好提交,进入command.do,再返回页面info.jsp

5.出现乱码问题解决方法
   5.1 控制台tomcat输出中文乱码
	点击tomcat设置页面,在VM options中输入-Dfile.encoding=UTF-8,下面两个下拉框都选Update classes and resources,确定,重启tomcat
   5.2 POST请求乱码
	<!-- 配置编码过滤器  -->
  	<filter>
  		<filter-name>EncodingFilter</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>EncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
   5.3 GET请求乱码
	Tomcat8 默认进行了url编码,get请求不乱码,Tomcat7会乱码
	在server.xml中配置
		<Connector URIEncoding="UTF-8" connectionTimeout="2000" port="8080"........(省略)

6.注解配置
   6.1 修改DispatchServelt-sevlet配置文件:
	<?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:mvc="http://www.springframework.org/schema/mvc"
	       xmlns:context="http://www.springframework.org/schema/context"
	       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	       xsi:schemaLocation="http://www.springframework.org/schema/beans
			http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
			http://www.springframework.org/schema/mvc
			http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
			http://www.springframework.org/schema/context
			http://www.springframework.org/schema/context/spring-context-3.2.xsd
			http://www.springframework.org/schema/aop
			http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
			http://www.springframework.org/schema/tx
			http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
	
	    <!--注解配置控制器-->
	    <!--▶1.配置扫描包-->
	    <context:component-scan base-package="com.dm.backoffice.web.controller"/>
	
	    <!--▶2.配置处理映射-->
	    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
	
	    <!--▶3.配置适配器-->
	    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
	
	    <!--4.配置资源视图解析器-->
	    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	        <!--前缀和后缀,方便查找jsp-->
	        <property name="prefix" value="/WEB-INF/views/"></property>
	        <property name="suffix" value=".jsp"></property>
	    </bean>
	
	</beans>
   6.2 控制层代码
	@Controller
	@RequestMapping("/user")
	public class UserController  {
	
	    @RequestMapping("/list")
	    public String list(){
	        return "user/userlist";		//▶访问/user/list.do即可进入该方法,并返回页面userlist(之所以需要.do是因为web.xml中配置了过滤器)。如果类上去除注解@RequestMapping("/user"),那就直接用方法上面的url来访问即可
	    }	
	}

7.表单接收页面数据的方式
   7.1 方法一:直接在方法参数中写,会自动转过来
	■register.jsp(通过/user/toRegister.do访问)
	<html>
	<head>
	    <title>Title</title>
	</head>
	<body>
	<form action="${pageContext.request.contextPath}/user/register.do" method="post">	▶设置提交路径
	    用户名:<input type="text" name="username"><br>
	    密码:<input type="text" name="password"><br>
	    性别:<input type="text" name="gender"><br>
	    年龄:<input type="text" name="age"><br>
	    生日:<input type="text" name="birthday"><br>
	    爱好:<input type="checkbox" name="hobbyIds" value="1">打球
	    <input type="checkbox" name="hobbyIds" value="2">打人
	    <input type="checkbox" name="hobbyIds" value="3">打假<br>
	    <input type="submit">
	</form>
	</body>
	</html>
	■Controller
	@Controller
	@RequestMapping("/user")
	public class UserController  {
	
	    @RequestMapping("/list")
	    public String list(){
	        return "user/userlist";
	    }
	
	    @RequestMapping("/toRegister")	//▶进入注册页面
	    public String toRegister(){
	        return "user/register";
	    }
	
	    @RequestMapping("/register")
	    public String register(String username, String password, int age, String gender, Date birthday,String[] hobbyIds){	//▶直接把页面上的变量写进参数
	        System.out.println(username);
	        System.out.println(password);
	        System.out.println(age);
	        System.out.println(gender);
	        System.out.println(birthday);		//▶date的参数在页面上必须采用标准的XX/XX/XX(三个里面必须有年月日)格式,否则转不了
	        System.out.println(Arrays.toString(hobbyIds));
	        return "user/info";
	    }
	}
   7.2 方法二:将变量封装进pojo(User)
	■Controller中方法
	@RequestMapping("/register2")
	    public String register(User user){
	        System.out.println(user);
	        return "user/info";
	    }
   7.3 方法三:接收包装类型参数(用一个UserExt类,其中含有一个成员User。相当于一个包装类)
	■Controller中方法
	@RequestMapping("/register3")
	    public String register3(UserExt userExt){
	        System.out.println(userExt);
	        return "user/info";
	    }
	■相应jsp中变量的name也需要改为user.XXX的格式
   	    用户名:<input type="text" name="user.username"><br>
	    密码:<input type="text" name="user.password"><br>
	    性别:<input type="text" name="user.gender"><br>
   7.4 如何接收集合(List和Map)
	■包装类中放入一个链表
	public class UserExt {
	    private User user;
	    private List<User> users=new ArrayList<>();
	    private Map<String,Object> infos=new HashMap<>();		//(get set toString都省略)
	}
	■Controller方法
	@RequestMapping("/register4")
	    public String register4(UserExt userExt){
	        System.out.println(userExt.getUsers());
		  System.out.println(userExt.getInfos());
	        return "user/info";
	    }
	■register.jsp(jsp中集合名要和UserExt保持一致,/user/toRegister.do访问)
	<body>
	接收集合类型参数<br>
	<form action="${pageContext.request.contextPath}/user/register4.do" method="post">
	    用户名1:<input type="text" name="users[0].username"><br>				▶链表中元素写法
	    密码1:<input type="text" name="users[0].password"><br>
	    <hr>
	    用户名2:<input type="text" name="users[1].username"><br>
	    密码2:<input type="text" name="users[1].password"><br>
	    <input type="submit" value="保存">
	</form>
	<br>
	接收Map类型参数<br>
	<form action="${pageContext.request.contextPath}/user/register5.do" method="post">
	    用户名1:<input type="text" name="infos['username']"><br>				▶Map中元素写法
	    密码1:<input type="text" name="infos['password']"><br>
	    <input type="submit">
	</form>
	</body>

8.SpringMVC和Struts的区别
   8.1 实现机制:Struts2是基于过滤器实现的。Springmvc基于servlet实现。
	   运行速度:Servlet比过滤器快。
   8.2 Struts2是多例,每一次请求,都会创建一个Action对象。请求来了以后,struts2创建多少个对象:ActionContext,valuestack,UAction,ActionSuport,ModelDriven
	   Springmvc是单例。同一个Controller请求,只会创建一个Controller
   8.3 参数封装来分析:Struts基于属性进行封装,Action有参数属性。
						 Springmvc基于方法封装,参数是写在Controller的方法。

9.其他说明
   9.1 model传递数据
	jsp:<a href="${pageContext.request.contextPath}/user/edit.do?id=${user.id}">修改</a>
	controller:
		@RequestMapping("/edit")
		    public String edit(int id ,Model model){
		        User user=new User("seds",17,"dfdf",new Date());		//模拟
		        user.setId(id);
		        model.addAttribute("user",user);
		        return "user/useredit";
		    }
   9.2 url模版映射:可以restfull软件架构
	jsp采用另外一种连接写法:<a href="${pageContext.request.contextPath}/user/edit1/${user.id}/${user.username}.do">修改</a>	▶将参数拼接在url中
	controller:
		@RequestMapping("/edit1/{id}/{username}")
		    public String edit1(@PathVariable int id ,@PathVariable String username, Model model){			▶@PathVariable可直接拿到参数
		        User user=new User("seds",17,"dfdf",new Date());
		        user.setId(1);
		        model.addAttribute("user",user);
		        return "user/useredit";
		    }
	web.xml需要在配置一套url过滤:							
		<servlet-mapping>
		        <servlet-name>DispatcherServlet</servlet-name>
		        <url-pattern>/rest/*</url-pattern>								▶访问http://localhost:8080/rest/user/edit1/1/1和上面http://localhost:8080/user/edit1/1/1.do效果是一样的
		</servlet-mapping>
   9.3 转发与重定向(转发地址不变,重定向改变)
		@RequestMapping("test1")
		    public String test1(){
		        return "forward:list.do";			//同一个控制器的转发(会转到list.do的控制器)
		    }
		
		@RequestMapping("/test1")
		    public String test1(){
		        return "forward:/user/list.do";		//不同控制器的转发(会转到/user/list.do的控制器)
			  return "redirect:/user/list.do";		//重定向(同一个控制器的重定向就不演示了,类似的)
		    }
   9.4 RequestParam参数
	/**
	 * RequestParam参数描述
	 * value:参数名称
	 * defaultValue:默认值
	 * required:参数是否必须有值,如果为true,参数又为空,会报错(存在默认值时该属性就没用了)
	* */
	@RequestMapping("/test2")
	    public String test2(@RequestParam(value="uid",required=true,defaultValue = "20") Integer uid){
        	  System.out.println(uid);		//http://localhost:8080/user/test2.do?uid=100打印100;http://localhost:8080/user/test2.do打印20
	        return "forward:list.do";
	    }
   9.5 想使用标签<c:forEach items="${userList}" var="user">,需要jsp页面添加<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>,
	   引入jar支持:F:\BaiduNetdiskDownload\2019年4月黑马程序员教程\01-黑马IDEA版本Java基础+就业课程\4.框架\Java开发工具\jar包\jstl-X.X.jar

















DOWN 返回