笔记10:springMVC

三层结构

                                    框架
表现层(web层):			springMVC
业务层(service层):		spring
持久层(dao层):			MyBatis

表现层一般使用MVC设计模型

M:model模型			例如javaBean等
V:view视图				例如jsp、html等
C:Controller控制器 	例如Servlet等

springMVC:基于java实现MVC设计模型的请求驱动类型的轻量级Web框架,属于springFrameWork的后续产品

springMVC和Struts2区别

相同:都是基于MVC模型编写、底层都离不开原始ServletAPI、处理请求机制都是一个核心控制器
不同:
	1-springMVC入口是一个Servlet,struts2是Filter
	2-springMVC基于方法设计,struts2是基于类,stuts2每次会创建一个动作类,所以springMVC快些
	3-springMVC使用更简洁,同时支持JSR303,处理ajax请求更方便
	4-struts2的OGNL表达式使页面开发效率更高些,但执行效率没比JSTL提升,尤其struts2表单标签远没有html执行效率高

springMVC入门程序

需求:index.jsp点击超链接转发到成功jsp页面

----搭建开发环境
	1-导入jar包
	2-web.xml配置springMVC核心控制器
		<servlet>
			<servlet-name>DispatcherServlet</servlet-name>
			<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
			<init-param><!--初始化加载springmvc配置文件-->
				<param-name>contextConfigLocation</param-name>
				<param-value>classpath:springmvc.xml</param-value>
			</init-param>
			<load-on-startup>1</load-on-startup>
		</servlet>
		<servlet-mapping>
			<servlet-name>DispatcherServlet</servlet-name>
			<url-pattern>/</url-pattern>
		</servlet-mapping>
	3-创建springmvc配置文件并配置
		<!-- 配置创建 spring 容器要扫描的包 -->
		<context:component-scan base-package="cn.xiaoai"></context:component-scan>
		<!-- 配置视图解析器 -->
		<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
			<property name="prefix" value="/"></property>
			<property name="suffix" value=".jsp"></property>
		</bean>
		<!--开启spr ingMVC框架注解的支持-->
		<mvc:annotation-driven></mvc:annotation-driven>

springMVC处理流程:

1-Request请求,然后进入DispatcherServlet
2-DispatcherServlet(前端控制器)	
	--》Handler(处理映射器):返回控制类和对应方法
	--》HandlerAdapter(处理适配器): 执行方法后并获得请求页面封装成视图模型返回
	--》ViewResolver(视图解析器):解析视图模型并返回
	渲染视图并把模型数据填充到request域中
3-DispatcherServlet最后response响应

【@RequestMapping】注解属性:

1-value==等于path,表示方法映射路径		
	valu="/hello"
2-path==表示方法映射路径					
	path="/hello"	
3-method==表示请求的方式 需要一个对象 可以传多个值{},通过RequestMethod.来获得对应方式 
	method={RequestMethod.POST} 请求为post,方法才执行
4-params==请求必须携带的参数	
	params={"username"} 请求必须携带username这个参数,方法才执行
	params={"username=heihei"} 请求必须携带username这个参数并且值为heihei,方法才执行
5-heades==限制请求消息头的条件
	heades={"Accept"} 请求必须包含请求头Accept,方法才执行

请求参数的绑定:

1-直接在方法参数中定义与传递参数相同名称的参数,(底层通过反射获取方法参数绑定)
	方法:
		@RequestMapping("/testParam")
		public String testParam(String username,String password){
			System.out.println("----------testParam()执行了");
			System.out.println(username+"--"+password);
			return "success";
		}
	视图页面:<a href="paramCTL/testParam?username=xiaoai&&password=111111">请求参数的绑定</a>
2-绑定到JavaBean对象
	参数名称和bean对象的set方法去掉set首字母小写的名称一致
	当JavaBean对象引用另一个JavaBean对象,则传参的名称可以多层引用,如:JavaBean对象引用了User对象则可以使用user.xx属性等。
	方法:
		@RequestMapping("/saveAccount")
		public String saveAccount(Account account){
			System.out.println("----------saveAccount()执行了");
			System.out.println(account);
			return "success";
		}
	视图页面:
		<form action="/paramCTL/saveAccount" method="post">
			姓名:<input type="text" name="username" placeholder="姓名"><br/>
			密码:<input type="text" name="password" placeholder="密码"><br/>
			金额:<input type="text" name="money" placeholder="金额"><br/>
			用户姓名:<input type="text" name="user.uname" placeholder="用户姓名"><br/>
			用户年龄:<input type="text" name="user.age" placeholder="用户年龄"><br/>
			<input type="submit"  value="提交"><br/>
		</form>
3-绑定到list或map
	<form action="paramCTL/saveAccount" method="post">
		姓名:<input type="text" name="username" placeholder="姓名"><br/>
		密码:<input type="text" name="password" placeholder="密码"><br/>
		金额:<input type="text" name="money" placeholder="金额"><br/>
		list用户姓名:<input type="text" name="list[0].uname" placeholder="用户姓名"><br/>
		list用户年龄:<input type="text" name="list[0].age" placeholder="用户年龄"><br/>
		map用户姓名:<input type="text" name="map['one'].uname" placeholder="用户姓名"><br/>
		map用户年龄:<input type="text" name="map['one'].age" placeholder="用户年龄"><br/>
		<input type="submit"  value="提交"><br/>
	</form>

springMVC中文乱码的解决:(过滤器)

----web.xml中配置
	<!--配置解决中文乱码的过滤器-->
	<filter>
		<filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

自定义类型转换器

例如:当属性为date类型传入了一个参数字符串为2020-11-11不符合date类型格式时会报错
	此时需要用自定义类型转换器来完成
1-先写程序:需要实现Converter接口
	public class StringToDateConverter implements Converter<String,Date>{
		/**
		 *
		 * @param source 传入的字符串
		 * @return
		 */
		@Override
		public Date convert(String source) {
			//判断
			if (source == null){
				throw new RuntimeException("请传入数据");
			}
			DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
			try {
				//把字符串转换日期
				return df.parse(source);
			} catch (Exception e) {
				throw new RuntimeException("数据类型转换出现错误");
			}
		}
	}
2-springMVC.xml配置文件中配置自定义类型转换器(注册)
	<!--配置自定义类型转换器-->
	<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
		<property name="converters" >
			<set><!--添加自定义的类型转换器-->
				<bean class="cn.xiaoai.utils.StringToDateConverter"></bean>
			</set>
		</property>
	</bean>
3-使转换器生效
	<!--开启springMVC框架注解的支持-->
	<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>

在核心控制器中拿到servlet原生api

直接在方法参数里获取即可
@RequestMapping("/testServlet")
public String testServlet(HttpServletRequest request, HttpServletResponse response){
    System.out.println("----------testServlet()执行了");
    System.out.println(request);

    HttpSession session = request.getSession();
    System.out.println(session);

    ServletContext servletContext = session.getServletContext();
    System.out.println(servletContext);

    System.out.println(response);
    return "success";
}

常用注解

1--【@RequestParam】==把请求中指定名称的参数给控制器中形参赋值
	属性value:请求参数名称
	属性required:请求参数中是否必须提供此参数。默认true,表示必须提供,不提供则报错。
	==使用例子========================================
	方法:
		@RequestMapping("/testRequestParam")
		public String testRequestParam(@RequestParam(value = "name") String username){
			System.out.println("----------testRequestParam()执行了");
			System.out.println(username);//输出:xioaai
			return "success";
		}
	页面视图:<a href="anno/testRequestParam?name=xiaoai">RequestParam</a>

2--【@RequestBody】==用于获取请求体内容。直接使用得到是key=value&key=value.....结构的数据  get请求方式不适用
	属性required:是否必须有请求体。默认true,get请求报错,为false,get请求到null。
	==使用例子========================================
	@RequestMapping("/testRequestBody")
	public String testRequestBody(@RequestBody String body){
		System.out.println("----------testRequestBody()执行了");
		System.out.println(body);//输出:username=xxx&age=xxx。xxx为表单里对应的输入值
		return "success";
	}
	页面视图:
		<form action="anno/testRequestBody" method="post">
			用户姓名:<input type="text" name="username" placeholder="用户姓名"><br/>
			用户年龄:<input type="text" name="age" placeholder="用户年龄"><br/>
			<input type="submit"  value="提交"><br/>
		</form>

3--【RequestHeader】==用于获取请求消息头	注:实际开发中一般不怎么用
	属性value:指定消息头名称
	属性required:是否必须有此消息头
	==使用例子========================================
	@RequestMapping("/testRequestHeader")
	public String testRequestHeader(@RequestHeader(value = "Accept") String header){
		System.out.println("----------testRequestHeader()执行了");
		System.out.println(header);
		return "success";
	}
	
4--【@PathVariable】==绑定url中的占位符。
	例如:请求url中 /delete/{id},这个{id}就是url占位符。 
	属性vlue:用于指定url中占位符名称
	属性required:是否必须提供占位符。
	==使用例子========================================
	@RequestMapping("/testPathVariable/{sid}")
	public String testPathVariable(@PathVariable(name = "sid")String id){
		System.out.println("----------testPathVariable()执行了");
		System.out.println(id);//输出10
		return "success";
	}
	视图页面: <a href="anno/testPathVariable/10">PathVariable</a>
	
5--【@CookieValue】==获取某个cookie的数据
	属性value:指定cookie名称
	属性required:是否必须有此cookie
	==使用例子========================================
	public String testCookieValue(@CookieValue(value = "JSESSIONID") String cookieValue){
		System.out.println("----------testCookieValue()执行了");
		System.out.println(cookieValue);
		return "success";
	}
	
6--【@ModelAttribute】
	属性value:用于获取数据的key。可是pojo的属性名称,也可是map结构的key。
	----放在方法上:表示当前方法会在控制器的方法执行之前先执行
		@RequestMapping("/testModelAttribute")
		public String testModelAttribute(User user){
			System.out.println("----------testCookieValue()执行了");
			System.out.println(user);//输出:user信息并且date带有数据
			return "success";
		}
		/**
		 *由于该方法先执行,直接返回数据即可
		 * @param uname
		 * @return
		 */
		@ModelAttribute
		public User showUser(String uname){
			System.out.println("----------showUser()方法执行了。。");
			User user = new User();
			//通过用户查询数据库(模拟)
			user.setUname(uname);
			user.setAge(20);
			user.setDate(new Date());
			return user;
		}
	----放在参数上:获取指定的数据给参数赋值
		@RequestMapping("/testModelAttribute")
		public String testModelAttribute(@ModelAttribute("abc") User user){
			System.out.println("----------testCookieValue()执行了");
			System.out.println(user);//输出:user信息并且date带有数据
			return "success";
		}
		/**
		 *把数据存入map,再从map取数据复制赋值给参数
		 * @param uname
		 * @return
		 */
		@ModelAttribute
		public void showUser(String uname, Map<String,User> map){
			System.out.println("----------showUser()方法执行了。。");
			User user = new User();
			//通过用户查询数据库(模拟)
			user.setUname(uname);
			user.setAge(20);
			user.setDate(new Date());
			map.put("abc",user);
		}
	
	视图页面:
		<form action="anno/testModelAttribute" method="post">
			用户姓名:<input type="text" name="uname" placeholder="用户姓名"><br/>
			用户年龄:<input type="text" name="age" placeholder="用户年龄"><br/>
			<input type="submit"  value="提交"><br/>
		</form>

7--【@SessionAttribute】==用于多次执行控制器方法间的参数共享。只能作用于类上
	属性value:指定存入的属性名称
	属性type:指定存入数据的类型
	@Controller
	@RequestMapping("/anno")
	@SessionAttributes(value = {"SessionAttribute-msg"})//把SessionAttribute-msg=xiaoai存入到session域中
	public class AnnoController {
		//存入信息
		@RequestMapping("/testSessionAttribute")
		public String testSessionAttribute(Model model){
			System.out.println("----------testSessionAttribute()执行了");
			model.addAttribute("SessionAttribute-msg","xioaai");
			return "success";
		}
		//获取信息
		@RequestMapping("/getSessionAttribute")
		public String getSessionAttribute(ModelMap modelMap){
			System.out.println("----------getSessionAttribute()执行了");
			String SessionAttribute_msg = (String) modelMap.get("SessionAttribute-msg");
			System.out.println(SessionAttribute_msg);
			return "success";
		}
		//删除信息
		@RequestMapping("/delSessionAttribute")
		public String delSessionAttribute(SessionStatus status){
			System.out.println("----------delSessionAttribute()执行了");
			status.setComplete();
			return "success";
		}
	}

REST风格URL:

通过请求方式来判断执行那一个方法

----当请求路径和请求方法一致时:通过url占位符来判断
	path = "/user" method="get"
	findAll()
	
	path = "/user/{id}" method="get"
	findById()
	
	localhost:8080/user/10 get  直接带变量10访问即可 不用localhost:8080/user?id=10 get
	@PathVariable注解即用来取占位符的值
	
restful优点:结构清晰、符合标准、易于理解、扩展方便

基于HiddentHttpMethodFilter过滤器

form表单只支持GET和POST请求,DELETE/PUT等并不支持,
spring3.0添加了过滤器HiddentHttpMethodFilter可将浏览器请求改为指定请求方式
通过表单hidden隐藏标签,修改请求方式

其他类如WebClient使用静态方法发送请求,也可模拟各种请求

响应之返回值

1-String字符串  方法执行并跳转到名称为返回值字符串页面    底层最终也会选择ModelAndView的方式跳转
	@RequestMapping(value = "/testString")
	public String testString(Model model){
		System.out.println("----------testString()执行了。。。");
		//模拟从数据库中查询出User对象
		User user = new User();
		user.setUsername("xiaoai");
		user.setPassword("123");
		user.setAge(21);
		//model对象存入数据
		model.addAttribute("user",user);
		return "success";
	}
2-void		方法执行,然后再次请求路径
	@RequestMapping(value = "/testVoid")
	public void testVoid(Model model){
		System.out.println("----------testVoid()执行了。。。");
	}
	跳转1----可以在视图目录下创建最后一级目录为名称的视图
	跳转2----请求转发
		@RequestMapping(value = "/testVoid")
		public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception {
			System.out.println("----------testVoid()执行了。。。");
			//编写请求转发的语句  请求转发:一次请求,不用编写项目的名称
			//请求转发不再调用视图解析器,如果有多级目录要手动加上
			request.getRequestDispatcher("success.jsp").forward(request,response);
			return;
		}
	跳转3----重定向
		@RequestMapping(value = "/testVoid")
		public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception {
			System.out.println("----------testVoid()执行了。。。");
			//重定向
			response.sendRedirect(request.getContextPath()+"/success.jsp");
			return;
		}
	跳转4----直接响应
		@RequestMapping(value = "/testVoid")
		public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception {
			System.out.println("----------testVoid()执行了。。。");
			//直接进行响应
			//--设置中文乱码
			response.setCharacterEncoding("UTF-8");
			response.setContentType("text/html;charset=UTF-8");
			//--响应
			response.getWriter().print("你好。直接响应");
			return;
		}

3--返回值为ModelAndView类型
	@RequestMapping(value = "/testModelAndView")
	public ModelAndView testModelAndView(){
		System.out.println("----------testModelAndView()执行了。。。");
		//创建ModelAndView对象
		ModelAndView mv = new ModelAndView();
		//模拟从数据库中查询出User对象
		User user = new User();
		user.setUsername("xiaoai");
		user.setPassword("123");
		user.setAge(21);
		//把user对象存储到mv中,底层也会把user存入到request对象域中
		mv.addObject("user",user);
		//跳转到那个页面可以设置
		mv.setViewName("success");
		return mv;
	}

响应之使用forword和redirect

请求转发和重定向是用不了视图解析的,所以路径问题需要注意
1--forward
	@RequestMapping(value = "/testForword")
	public String testForword(){
		System.out.println("----------testForword()执行了。。。");
		return "forward:/susccess.jsp";//路径需要自己手动填写其准确路径
	}
2--redirect
	@RequestMapping(value = "/testRedirect")
	public String testRedirect(){
		System.out.println("----------testRedirect()执行了。。。");
		return "redirect:/suscces.jsp";//通过关键字来重定向返回可以不加项目名,框架默认帮加 
	}

响应json数据

1--过滤静态资源
	默认核心控制器过滤掉了静态资源,需要解决:在springMVC配置文件中配置静态资源不拦截
	<!--前端控制器,哪些静态资源不拦截-->
	<mvc:resources location="/css/" mapping="/css/**"/>  <!-- 样式 -->
	<mvc:resources location="/images/" mapping="/images/**"/>  <!-- 图片 -->
	<mvc:resources mapping="/js/" location="/js/**"></mvc:resources>

--模拟ajax异步请求
	$("#btn").click(function () {
		//发送ajax请求
		$.ajax({
			//编写json格式,设置属性和值
			url:"user/testAjax",
			contentType:"application/json;charset=UTF-8",
			data:'{"username":"xiaoai","password":"123","age":"21"}',
			dataType:"json",
			type:"post",
			success:function (data) {
				//data表示服务器响应的json数据,进行解析
				alert(data);
				alert(data.username);
				alert(data.password);
				alert(data.age);
			}
		});
    });
	------------------------------------------控制器方法
	@RequestMapping(value = "/testAjax")
	public @ResponseBody User testAjax(@RequestBody User user){
		System.out.println("----------testAjax()执行了。。。");
		//客户端发送ajax异步请求,传递的是json字符串,后端把json字符串封装到user对象中
		System.out.println(user);
		//做响应,模拟查询数据库
		user.setUsername("haha");
		user.setAge(31);
		//做响应
		return user;
	}

springMVC提供的文件上传

1--文件上传回顾:
	a-form表单enctype(表单请求正文的类型)取值必须是multipart/form-data(默认为:application/x-www-form-urlencoded)
	b-method属性必须为post
	c-提供一个文件选择域(<input type="file" /> )
2--上传原理分析
	a-form表单enctype取值不是默认,request.getParameter()失效。
	b-enctype="application/x-www-form-urlencoded"时,form表单正文内容:key=value&key=value&....
	c-enctype="multipart/form-data"时,form表单正文内容:每部分都是MIME类型描述的正文
		-----------------------------7de1a433602ac   			分界符 
		Content-Disposition: form-data; name="userName"  		协议头 
		aaa              										协议的正文 
		-----------------------------7de1a433602ac 
		Content-Disposition: form-data; name="file"; 
		filename="C:\Users\zhy\Desktop\fileupload_demofile\b.txt" 
		Content-Type: text/plain         						协议的类型(MIME 类型) 
		 
		bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 
		-----------------------------7de1a433602ac-- 
		
3--借助第三方组件实现文件上传
	使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:
	Commons-fileupload 和commons-io。
	commons-io 不属于文件上传组件的开发 jar 文件,
	但Commons-fileupload 组件从 1.1 版本开始,它工作时需要 commons-io 包的支持。 

4--传统方式文件上传	
	@RequestMapping(value = "/fileUpload1")
	public String fileUpload1(HttpServletRequest request) throws Exception {
		System.out.println("----------fileUpload1()执行了。。。文件上传");
		//使用fileupload组件完成文件上传
		//1-文件上传位置
		String path = request.getSession().getServletContext().getRealPath("/uploads/");
		//2-判断该路径是否存在
		File file = new File(path);
		if (!file.exists()){
			file.mkdirs();
		}
		//3-解析request对象,获取上传文件项
		DiskFileItemFactory factory = new DiskFileItemFactory();
		ServletFileUpload upload = new ServletFileUpload(factory);
		//解析request
		List<FileItem> items = upload.parseRequest(request);//全是文件项
		//遍历
		for (FileItem item:items){
			//进行判断,当前item对象是否是上传文件项
			if (item.isFormField()){ //说明是普通表单项

			}else{ //说明是上传文件项
				//获取上传文件名称
				String fileName = item.getName();
				//把文件名称设置为唯一值
				String uuid = UUID.randomUUID().toString().replace("-", "");
				fileName = uuid+"_"+fileName;
				//完成文件上传
				item.write(new File(path,fileName));//写到某个路径下
				item.delete();
			}
		}
		return "success";
	}
	视图页面:
		<form action="fileUploadCTRL/fileUpload1" method="post" enctype="multipart/form-data">
			选择文件:<input type="file" name="upload" ><br/>
			<input type="submit" value="上传"><br/>
		</form>
5--springMVC方式文件上传
	----原理分析
		文件 --》request --》前端控制器 --》配置的文件解析器:解析request,获取上传文件项项返回 --》
		前端控制器带着上传文件项 --》请求方法:通过MultipartFile类上传
	a-springMVC配置文件配置组件:
		<!--配置文件上传解析器 id名称必须为:multipartResolver-->
		<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
			<property name="maxUploadSize" value="10485760"></property>
		</bean>
	b-控制器方法:
		@RequestMapping(value = "/fileUpload2")
		public String fileUpload2(HttpServletRequest request,MultipartFile upload) throws Exception {
			System.out.println("----------fileUpload2()执行了。。。文件上传");
			//1-文件上传位置
			String path = request.getSession().getServletContext().getRealPath("/uploads/");
			//2-判断该路径是否存在
			File file = new File(path);
			if (!file.exists()){
				file.mkdirs();
			}
			//获取上传文件名称
			String fileName = upload.getOriginalFilename();
			//把文件名称设置为唯一值
			String uuid = UUID.randomUUID().toString().replace("-", "");
			fileName = uuid+"_"+fileName;
			//完成文件上传
			upload.transferTo(new File(path,fileName));
			return "success";
		}
	c-视图页面:	
		<form action="fileUploadCTRL/fileUpload2" method="post" enctype="multipart/form-data">
			选择文件:<input type="file" name="upload" ><br/><%--方法参数名称必须和该name一致--%>
			<input type="submit" value="上传"><br/>
		</form>

-------------------------------------------------------以前笔记记录的	
文件上传和下载
	--例子1(传统上传)
		//半框架实现上传
		@RequestMapping(value = "/up",method = RequestMethod.POST)
		public String up(@RequestParam("uploadFile") MultipartFile uploadFile ,String desc,HttpSession session) throws IOException {
			//获取文件上传的名称
			String fileName = uploadFile.getOriginalFilename();
			String path = session.getServletContext().getRealPath("photo")+File.separator+fileName;
			//获取输入输出流
			InputStream is = uploadFile.getInputStream();
			OutputStream os = new FileOutputStream(new File(path));
			//一个一个字节上传
	//		int i=0;
	//		while ((i=is.read())!=-1) {
	//			os.write(i);
	//		}
			//字节数组上传
			int i=0;
			byte[] flush = new byte[1024];
			while ((i=is.read(flush))!=-1) {
				os.write(flush,0,i);
			}
			os.close();
			is.close();
			return "success";
		}
	--例子2(框架直接上传)
		//利用框架实现上传
		@RequestMapping(value = "/up_old",method = RequestMethod.POST)
		public String up_old(@RequestParam("uploadFile") MultipartFile uploadFile ,String desc,HttpSession session) throws IOException {
			//获取文件上传的名称
			String fileName = uploadFile.getOriginalFilename();
			String finalFileName = UUID.randomUUID()+fileName.substring(fileName.lastIndexOf("."));//解决重名问题
			String path = session.getServletContext().getRealPath("photo")+File.separator+finalFileName;
			File file = new File(path);
			uploadFile.transferTo(file);
			return "success";
		}
		
	--例子(固定图片下载)
	@RequestMapping(value = "/down")
	public ResponseEntity<byte[]> down(HttpSession session ) throws IOException{
		//获取下载文件的路径
		String realPath = session.getServletContext().getRealPath("img");
		String finalPath = realPath + java.io.File.separator+"日向雏田.jpg";
		//读取要下载的文件
		InputStream is = new FileInputStream(finalPath);
		byte[] b = new byte[is.available()];//available()获取输入流所读取的文件的最大字节数
		is.read(b);
		//设置请求头
		HttpHeaders headers = new HttpHeaders();
		headers.add("Content-Disposition", "attachment;filename=zzz.jpg");
		//设置响应状态
		HttpStatus statusCode = HttpStatus.OK;
		ResponseEntity< byte[]> entity = new ResponseEntity<byte[]>(b, headers, statusCode);
		
		is.close();
		return entity;
	}
-------------------------------------------------------以前笔记记录的	

6--springMVC跨服务器方式的文件上传
	1--需要导入相应的jar包(该jar包由sun公司提供)
		com.sun.jersey:jersey-client:1.18.1
		com.sun.jersey:jersey-core:1.18.1
	2--
		@RequestMapping(value = "/fileUpload3")
		public String fileUpload3(MultipartFile upload) throws Exception {
			System.out.println("----------fileUpload3()执行了。。。跨服务器文件上传");
			//定义上传文件服务器路径
			String path = "http://localhost:9090/uploads/";
			//2-判断该路径是否存在
			File file = new File(path);
			if (!file.exists()){
				file.mkdirs();
			}
			//获取上传文件名称
			String fileName = upload.getOriginalFilename();
			//把文件名称设置为唯一值
			String uuid = UUID.randomUUID().toString().replace("-", "");
			fileName = uuid+"_"+fileName;
			//完成文件上传,跨服务器上传
			//创建客户端的对象
			Client client = Client.create();
			//和图片服务器进行连接
			WebResource webResource = client.resource(path + fileName);
			//上传文件
			webResource.put(upload.getBytes());
			return "success";
		}

springMVC异常处理

        产生的异常都是一层一层往上抛出的,不处理最后会抛出到浏览器。
	异常处理器组件:不把异常抛出到浏览器,通过异常处理器处理异常(把友好错误提示页面响应到浏览器)
	1--编写自定义异常类(做提示信息)
		public class SysException extends Exception{
			//存储提示信息的
			private String message;
			@Override
			public String getMessage() {
				return message;
			}
			public void setMessage(String message) {
				this.message = message;
			}
			public SysException(String message) {
				this.message = message;
			}
		}
	2--编写异常处理器(需要实现HandlerExceptionResolver接口)
		public class SysExceptionResolver implements HandlerExceptionResolver{
			@Override
			public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
				//获取异常对象
				SysException e = null;
				if (ex instanceof SysException){
					e = (SysException) ex;
				}else{
					e = new SysException("系统正在维护....");
				}
				//创建modelAndView
				ModelAndView  mv = new ModelAndView();
				mv.addObject("errorMsg", e.getMessage());
				mv.setViewName("errorPage");
				return mv;
			}
		}
	3--配置异常处理器(跳转提示页面) springMVC配置文件配置
		<!--配置异常处理器-->
		<bean id="sysExceptionResolver" class="cn.xiaoai.exception.SysExceptionResolver"></bean>
		
	4--控制器方法:
		@RequestMapping(value = "/testException")
		public String testException() throws SysException{
			System.out.println("----------testException()执行了。。。异常处理");
			try {
				//模拟异常
				int a = 10/0;
			} catch (Exception e) {
				//打印异常信息
				e.printStackTrace();
				//抛出自定义异常
				throw new SysException("服务器走丢了。。。。");
			}
			return "success";
		}
	5--视图页面:
		<h3>异常处理页面</h3>
		<a href="user/testException">异常处理</a>
		---------------------------------------------
		<h3>错误页面</h3>
		${errorMsg}<%--打印错误信息--%>

springMVC拦截器

----拦截器类似过滤器filter,可以一个或多个
	请求--》拦截器(执行放行前代码) --》controller
	响应《-- 拦截器(执行放行后代码)《-- 	
	
----拦截器和过滤器区别
	a-过滤器是servlet规范一部分,任何java web工程都能用,拦截器是springMVC框架自己的,只有springMVC框架才能用
	b-过滤器在url-pattern中配置/*后,所有访问的资源都拦截,拦截器只拦截访问的控制方法,访问的是jsp、html、css、image或js等不会进行拦截
	
----自定义拦截器:
	1-编写拦截器类(需要实现HandlerInterceptor接口)
		public class MyInterceptor1 implements HandlerInterceptor{
			//预处理,放行前执行的方法(controller方法执行前执行)   return false==不放行 true==放行 执行下一拦截器,没有则执行controller中方法
			@Override
			public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
				System.out.println("----------MyInterceptor1拦截器执行了。。。。放行之前的代码");
				return true;
			}
			//放行后执行的方法(controller方法执行后执行)
			@Override
			public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
				System.out.println("----------MyInterceptor1拦截器执行了。。。。放行之后的代码");
			}
			//最后执行的方法
			@Override
			public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
				System.out.println("----------MyInterceptor1拦截器执行了。。。。最后执行代码");
			}
		}
	2-配置拦截器(springMVC配置文件中配置)
		<!--配置拦截器-->
		<mvc:interceptors>
			<mvc:interceptor>
				<mvc:mapping path="/user/*"/><!--要拦截的具体的方法  /**==所有方法都拦截  /user/*==user路径下所有方法拦截-->
				<!--<mvc:exclude-mapping path=""></mvc:exclude-mapping>&lt;!&ndash;不要拦截的方法&ndash;&gt;-->
				<!--配置拦截器对象-->
				<bean id="myInterceptor1" class="cn.xiaoai.interceptor.MyInterceptor1"></bean><!--注册拦截器-->
			</mvc:interceptor>
		</mvc:interceptors>
	
	----当两个拦截器时执行顺序如下:
		----------MyInterceptor1拦截器执行了。。。。放行之前的代码
		----------MyInterceptor2拦截器执行了。。。。放行之前的代码
		----------testInterceptor()执行了。。。拦截器测试的控制器方法
		----------MyInterceptor2拦截器执行了。。。。放行之后的代码
		----------MyInterceptor1拦截器执行了。。。。放行之后的代码
		----------success.jsp执行了。。。
		----------MyInterceptor2拦截器执行了。。。。最后执行代码
		----------MyInterceptor1拦截器执行了。。。。最后执行代码

---------------------------------------------------------------day3

ssm整合

表现层(web层):springMVC框架
业务层:spring框架
持久层:myBatis框架


一定是用spring框架去整合其他两个框架    写配置文件或注解?怎么简单怎么来    选:配置文件*注解方式

----1-先配置每个框架,框架可以正常使用。

----2-spring整合springMVC  
	思路:service交由spring管理,在控制器方法中可以注入service对象并调用其方法,方法正常使用即spring和springMVC整合成功
	实现:在web.xml中加载了springMVC的配置文件,但spring配置文件还没有被加载,
			所以通过监听器把spring配置文件一起加载进来,把service交由spring管理,
		=====================================web.xml配置文件中配置监听器加载spring配置文件
		<!--配置spring的监听器, 默认只加载WEB-INF目录下的applicationContext.xml文件-->
		<listener>
			<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
		</listener>
		<!--设置配置文件的路径-->
		<context-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:applicationContext.xml</param-value>
		</context-param>

----3-spring整合myBatis
	思路:在service层中可以注入dao层并调用其方法,dao层功能实现即spring和myBatis整合成功。
	实现:在spring配置文件中配置使得spring的ioc容器中有相关dao接口代理对象
		=====================================spring.xml配置文件中配置整合myBatis
		<!--spring整合myBatis-->
		<!--==配置连接池-->
		<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
			<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
			<property name="jdbcUrl" value="jdbc:mysql:///ssm"></property>
			<property name="user" value="root"></property>
			<property name="password" value="root"></property>
		</bean>
		<!--==配置sqlSessionFactory对象-->
		<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
			<property name="dataSource" ref="dataSource"></property>
		</bean>
		<!--==配置AccountDao接口所在的包-->
		<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
			<property name="basePackage" value="cn.xiaoai.dao"></property>
		</bean>

		<!--配置spring框架声明式事务管理-->
		<!--===配置事务管理-->
		<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
			<property name="dataSource" ref="dataSource"></property>
		</bean>
		<!--===配置事务通知-->
		<tx:advice id="txAdvice" transaction-manager="transactionManager">
			<tx:attributes>
				<tx:method name="find*" read-only="true"/>
				<tx:method name="*" isolation="DEFAULT"></tx:method>
			</tx:attributes>
		</tx:advice>
		<!--===配置AOP增强-->
		<aop:config>
			<aop:advisor advice-ref="txAdvice" pointcut="execution(* cn.xiaoai.service.impl.*ServiceImpl.*(..))"></aop:advisor>
		</aop:config>

----当myBatis的配置文件的配置已经通过spring配置完,则myBatis配置文件可删除。
posted @ 2020-07-20 12:56  小艾影  阅读(166)  评论(0编辑  收藏  举报