SpringMVC注解开发的高级知识总结

SpingMVC注解开发的高级知识总结

数据回显

  • 数据回显的需求:表单提交出现错误,重新回到表单,同时用户重新填写数据,刚才提交的参数在页面上回显。
  • 执行的流程:点击修改连接---->携带id进入修改的controller---->修改页面.jsp---->提交修改好的页面—>失败的话将刚刚填写的数据进行重新显示

简单数据类型

  • 为了效果的展示,我们将隐藏的数据id显示出来。简单的数据回显,我们使用model.addAttribute方法设置key一致。

  • 首先进入修改页面的controller
    在这里插入图片描述

  • 数据在修改.jsp得到展示

  • 点击提交---->错误之后数据进行回显—>修改提交的controller中
    在这里插入图片描述

pojo数据类型的回显

  • 方法一:仍然使用model.addAttribute
    在这里插入图片描述
  • 方法二:使用@ModelAttribute,作用于将请求pojo数据放到Model中回显到页面
    ​ 在ModelAttribute方法指定的名称就是要填充Model中的key,在页面中就要通过key取数据。
    在这里插入图片描述

@ModelAttribute将方法返回值传到页面

  • 需求:商品类别信息在商品信息页面显示。
    ​ 比如商品通过筛选(根据商品的类型)
    SpringMVC注解开发的高级知识总结_第1张图片
    页面显示
    SpringMVC注解开发的高级知识总结_第2张图片
    使用@ModelAttribute将公用的取数据的方法返回值传到页面,不用在每一个controller方法通过Model将数据传到页面。

参数绑定集合类型

绑定数组

  • 需求:在商品查询列表页面,用户选择要删除的商品,批量删除商品。

  • 在controller方法中如何将批量提交的数据绑定成数组类型。

  • 页面传递数组的参数,使用 js 给普通的按钮组件添加批量删除(转跳到批量删除的controller)
    在这里插入图片描述

  • Item商品的controller接收:
    SpringMVC注解开发的高级知识总结_第3张图片

绑定List
  • 需求:批量修改商品信息提交

    ​ 先进入批量修改商品页面,填写信息,点击提交。

  • 在列表添加批量修改按钮,点击转跳到批量修改controller,
    SpringMVC注解开发的高级知识总结_第4张图片

  • 通过查询所有将结果展示批量修改.jsp
    SpringMVC注解开发的高级知识总结_第5张图片
    itemsList:controller方法形参包装类型中list的属性名。

    itemsList[0]或itemsList[1]。。,[]中是序号,从0开始。

    itemsList[].name:name就是controller方法形参包装类型中list中pojo的属性名

  • 商品完成修改之后进行提交(接收集合类型的参数)使用包装类型。
    SpringMVC注解开发的高级知识总结_第6张图片

商品的图片上传

  • 需求:在商品修改页面,增加图片上传的功能。

    操作流程:
    ​ 用户进入商品修改页面
    ​ 上传图片
    ​ 点击提交(提交的是图片和商品信息)
    ​ 再次进入修改页面,图片在商品修改页面展示

图片存储问题

​ 切记:不要把图片上传到工程 目录 ,不方便进行工程 维护。

​ 实际电商项目中使用专门图片服务器(http,比如apache、tomcat)。
​ 本教程使用图片虚拟目录,通过虚拟目录 访问硬盘上存储的图片目录 。
​ 图片目录中尽量进行目录分级存储,提高访问速度(提交i/o)。
​ 虚拟 目录 设置:
SpringMVC注解开发的高级知识总结_第7张图片

配置图片上传解析器

  • 依赖于:两个jar包
    springmvc使用commons-fileupload进行图片上传。
    commons-fileupload对应的springmvc的图片上传解析器:
    在这里插入图片描述
    在springmvc.xml的配置上传图片的解析器
    	
    	<bean id="multipartResolver"
    		class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    		
    		<property name="maxUploadSize">
    			<value>5242880value>
    		property>
    	bean>
    

编写上传图片的页面

  • 配置提交的action中的enctype="multipart/form-data"

  • 修改页面:
    SpringMVC注解开发的高级知识总结_第8张图片

  • 编写controller
    SpringMVC注解开发的高级知识总结_第9张图片

json数据的交互

  • springmvc解析json依赖的jar包:
    在这里插入图片描述

  • json数据配置的方式有两种:

  • 第一种:Springmvc默认用MappingJacksonHttpMessageConverter对json数据进行转换
    ​ 在处理器适配器中注入MappingJacksonHttpMessageConverter
    SpringMVC注解开发的高级知识总结_第10张图片

  • 第二种:使用:mvc:annotation-driven 对json数据响应提供支持

    	
    	<mvc:annotation-driven		conversion-service="conversionService" />
    

@RequestBody和@ResponseBody

  • @RequestBody:将请求的json数据转成java对象

  • @ResponseBody:将java对象转成json数据输出。
    SpringMVC注解开发的高级知识总结_第11张图片

请求json相应json

  • 请求页面

    function requestJson() {
    		$.ajax({
    			url : "${pageContext.request.contextPath }/requestJson.action",
    			type : "post",
    			contentType : "application/json;charset=utf-8",
    			//请求json数据,使用json表示商品信息
    			data : '{"name":"手机","price":1999}',
    			success : function(data) {
    				alert(data.name);
    			}
    		});
    	}
    
  • controller方法接收并返回:

    	// 传入Json响应Json
    	@RequestMapping("/requestJson")
    	public @ResponseBody ItemsCustom requestJson(@RequestBody ItemsCustom itemsCustom, HttpServletRequest request) {
            
    		return itemsCustom;
    	}
    

请求key/value相应json

  • 请求页面:

    function responseJson() {
    		$.ajax({
    			url : "${pageContext.request.contextPath }/responseJson.action",
    			type : "post",
    			// contentType : "application/json;charset=utf-8",
    			//请求json数据,使用json表示商品信息
    			data : "name=手机&price=3999",
    			success : function(data) {
    				alert(data.name);
    			}
    		});
    	}
    
  • controller方法接收并返回:

    	// 传入key/value响应Json
    	@RequestMapping("/responseJson")
    	public @ResponseBody ItemsCustom responseJson(ItemsCustom itemsCustom) {
    		return itemsCustom
    	}
    

统一异常处理

  • 需求:一般项目中都需要作异常处理,基于系统架构的设计考虑,使用统一的异常处理方法。

  • 系统中异常类型有哪些?

    包括预期可能发生的异常、运行时异常(RuntimeException),运行时异常不是预期会发生的。

    针对预期可能发生的异常,在代码手动处理异常可以try/catch捕获,可以向上抛出。

    针对运行时异常,只能通过规范代码质量、在系统测试时详细测试等排除运行时异常。

自定义异常

  • 针对预期可能发生的异常,定义很多异常类型,这些异常类型通常继承于Exception。

    这里定义一个系统自定义异常类:

    /**
     * 系统自定义的异常类型,实际开发中可能要定义多种异常类型
     * @author SYJ
     */
    public class CustomException extends Exception {
    	// 异常信息
    	private String message;
    	public CustomException() {
    		super();
    	}
    	public CustomException(String message) {
    		super();
    		this.message = message;
    	}
    	public String getMessage() {
    		return message;
    	}
    	public void setMessage(String message) {
    		this.message = message;
    	}
    }
    

统一异常分析

  • 要在一个统一异常处理的类中要处理系统抛出的所有异常,根据异常类型来处理。

  • 前端控制器DispatcherServlet在进行HandlerMapping、调用HandlerAdapter执行Handler过程中,如果遇到异常,进行异常处理。

  • DispatcherServlet的源码分析
    在这里插入图片描述

  • 在系统中自定义统一的异常处理器,写系统自己的异常处理代码。

定义统一异常处理器类

  • 定义统一异常处理器类

  • 根据不同的异常类型进行异常处理。

  • 系统自定义的异常类是CustomException,在controller方法中、service方法中手动抛出此类异常。

  • 针对系统自定义的CustomException异常,就可以直接从异常类中获取异常信息,将异常处理在错误页面展示

  • 针对非CustomException异常,对这类重新构造成一个CustomException,异常信息为“系统发生异常了,请联系管理员”,此类错误需要在系统测试阶段去排除。

    public class CustomExceptionResolver implements HandlerExceptionResolver {
    
    	@Override
    	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
    			Exception ex) {
    		// 输出异常(方便调试)
    		ex.printStackTrace();
    		// 定义异常信息在指定页面显示
    		String message = null;
    		CustomException customException = null;
    		// 统一处理异常代码
    		// 针对系统自定义的CustomException异常,就可以直接从异常类中获取异常信息,将异常信息在页面展示
    		// 异常信息
    		if (ex instanceof CustomException) {
    			customException = (CustomException) ex;
    		} else {
    			// 针对非CustomException异常,我们对这类的信息重新尽心异常类型的构造,异常信息为“系统发生异常了,请联系管理员”
    			customException = new CustomException("系统发生异常了,请联系管理员");
    		}
    		message = customException.getMessage();
    		request.setAttribute("message", message);
    		try {
    			request.getRequestDispatcher("/WEB-INF/jsp/error.jsp").forward(request, response);
    		} catch (ServletException | IOException e) {
    			e.printStackTrace();
    		}
    		return new ModelAndView();
    	}
    }
    
  • 将定义好的统一异常处理类在springmvc.xml中进行配置(因为实现了HandlerExceptionResolver接口所以不需要加bean的id)

    	
    	
    
  • 测试:
    SpringMVC注解开发的高级知识总结_第12张图片

  • 图解分析异常的统一处理
    SpringMVC注解开发的高级知识总结_第13张图片

RESTful支持

  • RESTful软件开发理念,RESTful对http进行非常好的诠释。

    RESTful即Representational State Transfer的缩写。
    SpringMVC注解开发的高级知识总结_第14张图片

url的RESTful实现

  • 非RESTful的http的url:http://localhost:8080/items/editItems.action?id=1&…

    RESTful的url是简洁的:http:// localhost:8080/items/editItems/1

    参数通过url传递,rest接口返回json数据

  • 需求:根据id查看商品信息,商品信息查看的连接使用RESTful方式实现,商品信息以json返回。

  • 第一步更改DispatcherServlet配置

     
      <servlet>
      	<servlet-name>springmvc_restservlet-name>
      	<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
      		
      		<init-param>
      			<param-name>contextConfigLocationparam-name>
      			<param-value>classpath:spring/springmvc.xmlparam-value>
      		init-param>
      servlet>
      <servlet-mapping>
      	<servlet-name>springmvc_restservlet-name>
      	
      	<url-pattern>/url-pattern>
      servlet-mapping>
    
  • 第二步参数通过url传递

    配置页面:
    在这里插入图片描述
    在controller中进行接收:

    	// RESTful测试
    	@RequestMapping("/viewItems/{id}")
    	// 根据商品id查看商品信息rest接口
    	// @RequestMapping中指定restful方式的ur1中的参教,参教需要用 { } 包起来
    	// @PathVariable将ur1中的 { } 包起参数和形参进行绑定
    	public @ResponseBody ItemsCustom viewItems(@PathVariable("id") Integer id) throws Exception {
    		// 调用 service查询商品信息
    		ItemsCustom itemsCustom = itemsService.findItemsById(id);
    		return itemsCustom;
    	}
    
  • 设置静态资源解析

    当DispatcherServlet拦截/开头的所有请求,对静态资源的访问就报错:

    需要通过设置对静态资源进行解析.

    访问/js/**的url从工程下/js/下解析。

    	
    	
    	<mvc:resources location="/js/" mapping="/js/**" />
    	<mvc:resources location="/img/" mapping="/img/**" />
    

SpringMVC拦截器

  • 用户请求到DispatherServlet中,DispatherServlet调用HandlerMapping查找Handler,HandlerMapping返回一个拦截的链儿(多个拦截),springmvc中的拦截器是通过HandlerMapping发起的。

    ​ 在企业开发,使用拦截器实现用户认证(用户登陆后进行身份校验拦截),用户权限拦截。
    SpringMVC注解开发的高级知识总结_第15张图片

springmvc拦截器方法

  • 需要实现HandlerInterceptor接口

    public class MyInterceptor1 implements HandlerInterceptor {
    
    	// 执行Handler之后执行
    	// 作为系统的统一异常处理,进行方法的执行性能的监控,在preHandler中设置一个时间点,在afterCompletion设置一个时间点,两个时间的差值
    	// 实现系统统一对日志的处理
    	@Override
    	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    			throws Exception {
    		System.out.println("MyInterceptor1...afterCompletion...");
    	}
    
    	// 在执行handler返回ModelAndView之前执行
    	// 如果需要向页面提供数据或者配配置视图信息,可以使用此方法从ModelAndView执行
    	@Override
    	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
    			ModelAndView modelAndView) throws Exception {
    		System.out.println("MyInterceptor1...postHandle...");
    	}
    
    	// 在handler之前执行
    	// 主要用于用户认证的校验、用户的权限校验
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		System.out.println("MyInterceptor1...preHandle...");
    		// 如果为true表示放行,如果返回false表示拦截之后不继续执行handler
    		return true;
    	}
    }
    

配置拦截器

  • 配置全局的拦截器,DispatcherServlet将配置的全局拦截器加载到所有的HandlerMapping。

    在springmvc.xml中配置:

    
    	<mvc:interceptors>
    		<mvc:interceptor>
    					<mvc:mapping path="/**" />
    					<bean class="com.syj.ssm.interceptor.MyInterceptor1">bean>
    		mvc:interceptor>
    			<mvc:interceptor>
    					<mvc:mapping path="/**" />
    					<bean class="com.syj.ssm.interceptor.MyInterceptor2">bean>
    		mvc:interceptor>
    	mvc:interceptors>
    

拦截器应用(用户认证拦截)

  • 需求:用户访问系统的资源(url),如果用户没有进行身份认证,进行拦截,系统跳转登陆页面,如果用户已经认证通过,用户可以继续访问系统
    的资源。

  • 登录页面的开发:

    <title>用户的登录</title>
    </head>
    <body>
    	<form action="${pageContext.request.contextPath }/login.action"  method="post">
    		用户名:<input type="text" name="usercode"  /><br>&nbsp;码:<input type="password" name="password"  /><br>
    		<input type="submit" value="登录"   >
    	</form>
    </body>
    </html>
    
  • 登录和退出的controller的开发:

    @Controller
    public class Login {
    
    	@RequestMapping("/login")
    	// 用户的登录提交的方法
    	public String login(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
    		// 调用service通过查询数据库,验证账号和密码的正确性
    		// 执行各种操作
    
    		// 获取用户名
    		String usercode = (String) request.getParameter("usercode");
    		// 将用户名存储到session中
    		session.setAttribute("usercode", usercode);
    		// 验证成功之后转跳到查询的列表
    		return "redirect:/item/queryItems.action";
    	}
    
    	// 用户的退出
    	@RequestMapping("/logout")
    	public String logout(HttpSession session) {
    		// session失效
    		session.invalidate();
    
    		return "redirect:/login.jsp";
    	}
    }
    
    
  • 拦截实现思路:
    SpringMVC注解开发的高级知识总结_第16张图片

  • 登录拦截器的开发:

    public class LoginInterceptor implements HandlerInterceptor {
    
    	@Override
    	public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
    			throws Exception {
    		System.out.println("LoginInterceptor ... afterCompletion ...");
    	}
    
    	@Override
    	public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
    			throws Exception {
    		System.out.println("LoginInterceptor ... postHandle ...");
    	}
    
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		System.out.println("LoginInterceptor ... preHandle ...");
    		// 1、如果url是公开地址(比如网站的首页人人都可以查看)
    		// 得到请求的地址
    		StringBuffer url = request.getRequestURL();
    		if (url.indexOf("login.action") >= 0) {
    			return true;
    		}
    
    		// 2、判断session中是否存在该用户
    		HttpSession session = request.getSession();
    		String usercode = (String) session.getAttribute("usercode");
    		// 如果存在就放行
    		if (usercode != null && usercode.length() > 0 && !"".equals(usercode.trim())) 		 {
    			return true;
    		}
    		// 执行到这里说明该用户没有登录或者不存在
    		request.getRequestDispatcher("/login.jsp").forward(request, response);
    
    		return false;
    	}
    }
    
  • 在springmvc.xml中配置拦截器:
    SpringMVC注解开发的高级知识总结_第17张图片

SpringMVC和Struts2的区别

  • springmvc是通过方法的形参接收参数,在使用时可以以单例方式使用,建议使用单例。

    struts是通过成员变量接收参数,在使用时必须以多例方式使用。

  • springmvc是基于方法开发,struts基于类开发。

    springmvc将一个请求的Method和Handler进行关联绑定,一个method对应一个Handler。

  • springmvc开发以方法为单位进行开发,方法更帖进service(业务方法)。

  • 经过实际测试,发现struts标签解析速度比较慢,建议在实际开发时使用jstl。

你可能感兴趣的:(SpringMVC)