SpringMVC02
响应数据呵结果视图
返回值分类
-
返回值为字符串
用于指定返回的逻辑视图名称; 控制器代码: @RequestMapping("/test1") public String test1(String pname){ System.out.println(pname); System.out.println("返回string类型测试"); return "main"; } -
void类型(servlet的api操作)
通常使用原始servlet处理请求时,返回该类型; 控制器代码: @RequestMapping("/test2") public void test2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("返回void类型测试"); request.getRequestDispatcher("/response/test1").forward(request,response); } -
ModelAndView
用于绑定参数和指定返回视图名称; 控制器代码: @RequestMapping("/test3") public ModelAndView test3(ModelAndView modelAndView){ modelAndView.addObject("aa","aa1"); modelAndView.setViewName("main"); return modelAndView; }
转发和重定向
-
forword请求转发
控制器代码: @RequestMapping("/test4") public String test4(){ System.out.println("我是请求转发"); return "forward:/response/test1"; } -
redirect重定向
控制器代码: @RequestMapping("/test5") public String test5(RedirectAttributes redirectAttributes,String pname){ System.out.println("我是重定向"); // redirectAttributes.addAttribute("pname",pname); redirectAttributes.addFlashAttribute("pname",pname); return "redirect:/response/test1"; } //注意:重定向携带参数,需要使用对象RedirectAttributes,该对象提供两个方法封装参数addAttribute()和addFlashAttribute(),第一个方法参数会明文显示在浏览器地址栏,第二个方法参会会隐藏,使用第二种方法传参时,获取参数时需要加注解@ModelAttribute;
响应json数据
servlet中异步响应json数据:
String jsonStr = JSON.toJsonString(List<User>)
response.getWriter().write("{key:value,key:value....}");
(1)导入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.4</version>
</dependency>
(2)编写代码
@RequestMapping("/showFruit")
@ResponseBody
public List<Fruit> showFruit(){
List<Fruit> list = new ArrayList<>();
for(int i=0;i<10;i++){
Fruit fruit = new Fruit();
fruit.setFname("apples"+i);
fruit.setFname("好吃"+i);
list.add(fruit);
}
System.out.println(list.size());
return list;
}
Rest风格编程
Rest风格URL规范介绍
-
restful介绍
- RESTful架构,就是目前最流行的一种互联网软件架构风格。
-
restful优点
- 结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
-
restful特性
-
资源
- 网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个 URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要获取这个资源,访问它的 URI 就可以,因此 URI 即为每一个资源的独一无二的识别符。
-
表现层
- 把资源具体呈现出来的形式,叫做它的表现层 (Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
-
状态转化
- 每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP 协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是“表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET 、POST 、PUT、DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
-
传统请求url
-
Rest风格请求
-
PathVariable注解详解
- 该注解用于绑定 url 中的占位符。例如:请求 url 中/annotation/test9/{id},这个{id}就是 url 占位符。url 支持占位符是 spring3.0 之后加入的。是springmvc 支持 rest 风格 URL 的一个重要标志。
- 属性:value:用于指定 url 中占位符名称。
required:是否必须提供占位符
案例
构建页面发起请求
REST风格编程:
新增:
<form action="/annotation/person" method="post">
用户名:<input name="userName" type="text">
年龄:<input name="age" type="text">
<input type="submit" value="提交">
</form>
修改:
<form action="/annotation/person" method="post">
<input type="hidden" name="_method" value="PUT">
用户名:<input name="userName" type="text">
年龄:<input name="age" type="text">
<input type="submit" value="提交">
</form>
删除:
<form action="/annotation/person/1" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="提交">
</form>
查询:
<a href="/annotation/person/1">查询用户</a>
定义控制层执行器处理请求
@RequestMapping(value = "person",method = RequestMethod.POST)
public String addPerson(String userName,int age){
System.out.println("新增用户:"+userName);
return "main";
}
@RequestMapping(value = "person",method = RequestMethod.PUT)
public String updatePerson(String userName,int age){
System.out.println("修改用户:"+userName);
return "main";
}
@RequestMapping(value = "person/{id}",method = RequestMethod.DELETE)
public String deletePerson(@PathVariable(value = "id")int id){
System.out.println("删除用户:id"+id);
return "main";
}
@RequestMapping(value = "person/{id}",method = RequestMethod.GET)
public String findPerson(@PathVariable(value = "id")int id){
System.out.println("查询用户信息:id"+id);
return "main";
}
引入请求方式转换过滤器
<filter>
<filter-name>hiddenMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
SpringMVC中的父子容器解析
SpringMVC中的父子容器解析
- Spring和SpringMVC的容器具有父子关系,Spring容器为父容器,SpringMVC为子容器,子容器可以引用父容器中的Bean,而父容器不可以引用子容器中的Bean。
SpringMVC中的文件上传
文件上传的必要前提
- form 表单的 enctype 取值必须是:multipart/form-data(默认值是:application/x-www-form-urlencoded)enctype:是表单请求正文的类型
- method属性取值必须是Post
- 提供一个文本选择域
文本上传原理分析
- 当 form 表单的 enctype 取值不是默认值后,request.getParameter()将失效。 enctype=”application/x-www-form-urlencoded”时,form 表单的正文内容是:key=value&key=value&key=value;
当 form 表单的 enctype 取值为 Mutilpart/form-data 时,请求正文内容就变成:每一部分都是 MIME 类型描述的正文;
SpringMVC上传文件
1、构建maven工程添加相关依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
2、编写 jsp 页面
<form enctype="multipart/form-data" method="post" action="/file/fileUpload">
<input type="file" name="file">
<input type="submit" value="上传">
</form>
3、编写控制器
@RequestMapping("/fileUpload")
public String fileUpload(MultipartFile file){
File dest = new File("C:\\Users\\mwx\\Pictures\\"+file.getOriginalFilename());
//文件上传
try {
file.transferTo(dest);
} catch (IOException e) {
e.printStackTrace();
}
return "main";
}
4、配置文件解析器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
文件下载
Spring文件下载使用内部工具类 ResponseEntity完成
制作文件下载控制器方法
@RequestMapping("/downloadFile")
public ResponseEntity<byte[]> downloadFile() throws Exception{
String fileName = "2018年上半年绩效考核.xls";
String path = "C:\\upload\\";
String newFileName = new String(fileName.getBytes("gbk"),"iso-8859-1");
File file = new File(path + fileName);
// 设置我们文件的响应头
HttpHeaders header = new HttpHeaders();
//指定输出的文件名称(硬编码以后的文件的名称)
header.setContentDispositionFormData("attachment",newFileName);
//设置我们的响应类型(MIME:text\html application\json text\xml image\jpeg)
header.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//利用SpringMVC的工具将我们指定的File对象中文件编译成字节数组
return
new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),header,HttpStatus.OK);
}
SpringMVC中的异常处理(只能处理controller包含的异常,了解api)
项目开发中异常处理的方式介绍
- 系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生。
异常处理的设计思路
- 系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理。
异常处理步骤
1、编写异常类和错误页面
@RequestMapping("/test2")
public String test2(){
System.out.println("模拟出现异常");
int i = 10/0;
return "main";
}
2、自定义异常处理器
public class MyExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ex.printStackTrace();
System.out.println("自定义异常处理");
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
return modelAndView;
}
}
3、配置异常处理器
<bean class="com.offcn.util.MyExceptionHandler"></bean>
SpringMVC中的拦截器使用(Filter 过滤器)
拦截器的介绍和作用
- SpringMVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。用户可以自己定义一些拦截器来实现特定的功能。—拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
拦截器和过滤器的区别
- 过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用
在web.xml中的 url-pattern 标签中配置了/*之后,可以对所有要访问的资源拦截。 - 拦截器是 SpringMVC 框架自己的,只有使用了SpringMVC框架的工程才能用。
只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者js是不会进行拦截的。它也是 AOP 思想的具体应用。
要求必须实现:HandlerInterceptor 接口。
自定义拦截器步骤
编写一个普通类实现 HandlerInterceptor 接口
public class MyIntercepter implements HandlerInterceptor {
/**
* 控制层执行器方法前的拦截器
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("我是控制层执行器方法前的拦截器");
//校验用户是否登录
HttpSession session = request.getSession();
String pname=(String)session.getAttribute("pname");
if(pname!=null){
//当前用户已经登录,放行
return true;
}else{
//当前用户未登录,拦截跳转到登录页面
request.getRequestDispatcher("/login.jsp").forward(request,response);
return false;
}
//返回true表示继续执行控制层执行器方法,返回false表示方法结束,不会执行控制层执行器方法
}
/**
* 控制层方法返回时拦截器
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
System.out.println("我是控制层执行器方法返回时拦截器");
}
/**
* 控制层方法结束后的拦截器
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
System.out.println("我是控制层执行器方法结束后的拦截器");
}
}
2、配置拦截器
<!--springMVC配置文件中注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/file/login"/>
<bean class="com.offcn.util.MyIntercepter"></bean>
</mvc:interceptor>
</mvc:interceptors>
拦截器注意事项
-
拦截器放行
- 如果有下一个拦截器就执行下一个,如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法。
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)方法返回true表示继续执行控制层执行器方法,返回false表示方法结束,不会执行控制层执行器方法。
- 如果有下一个拦截器就执行下一个,如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法。
-
拦截器中方法说明及放行情况
public class MyInterceptor2 implements HandlerInterceptor { /** * 控制层执行器方法前的拦截器(该方法是在控制层执行器方法前调用,当该方法返回结果为true则继续调用下一个拦截器,如果已经时最后 * 一个拦截器,则调用控制层中的执行器方法;当该方法返回结果为false,则不会继续执行控制层执行器中的方法) * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("我是控制器方法前拦截器2"); return true; } /** * 控制层方法返回时拦截器(该方法是控制层执行器方法执行之后,由DispatcherServlet在将结果响应给浏览器前调用的方法) * @param request * @param response * @param handler * @param modelAndView * @throws Exception */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { System.out.println("我是控制层执行器方法返回时拦截器2"); } /** * 控制层方法结束后的拦截器(该方法在请求业务处理执行完全结束之后由DispatcherServlet调用执行) * @param request * @param response * @param handler * @param ex * @throws Exception */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { System.out.println("我是控制层执行器方法结束后的拦截器2"); } } -
拦截器的作用路径
<!--拦截器注册--> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/><!--用于指定拦截的 url--> <mvc:exclude-mapping path="/file/login"/><!--用于指定排除的 url--> <bean class="com.offcn.util.MyIntercepter"></bean> </mvc:interceptor> </mvc:interceptors>
拦截器案例(验证用户是否登录)
实现思路分析
- 定义登录页面,并定义请求映射。
- 判断用户名密码是否正确
- 如果正确 向 session 中写入用户信息
- 返回登录成功。
- 拦截用户请求,判断用户是否登录
- 如果用户已经登录。放行
- 如果用户未登录,跳转到登录页面
案例
1、登录页面login.jsp定义:
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/file/login" method="post">
用户名:<input type="text" name="pname">
密码:<input type="text" name="password">
<input type="submit" value="登录">
</form>
</body>
</html>
2、控制器实现:
@RequestMapping("/login")
public String login(String pname, String password, HttpSession session){
System.out.println("登录校验成功");
//将登录成功的用户名存放到session中
session.setAttribute("pname",pname);
return "main";
}
3、拦截器实现:
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("我是控制层执行器方法前的拦截器");
//校验用户是否登录
HttpSession session = request.getSession();
String pname=(String)session.getAttribute("pname");
if(pname != null){
//当前用户已经登录,放行
return true;
}else{
//当前用户未登录,拦截跳转到登录页面
request.getRequestDispatcher("/login.jsp").forward(request,response);
return false;
}
//返回true表示继续执行控制层执行器方法,返回false表示方法结束,不会执行控制层执行器方法
}
4、注册拦截器:
<mvc:interceptor>
<mvc:mapping path="/**"/><!--用于指定拦截的 url-->
<mvc:exclude-mapping path="/file/login"/><!--用于指定排除的 url-->
<bean class="com.offcn.util.MyIntercepter"></bean>
</mvc:interceptor>

浙公网安备 33010602011771号