笔记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><!–不要拦截的方法–>-->
<!--配置拦截器对象-->
<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配置文件可删除。