springMVC
springMVC是一站式框架spring中的一个模块,方便前后端数据传输
详情可查看Workplace中的Maven07系列项目
<!-- spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<!-- jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
- 在配置文件中集成mvc约束
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
</beans>
- springmvc配置文件
值得注意的是springmvc的拦截器是不拦截.jsp文件的,只拦截控制器内部请求。
<!-- 开启springmvc注解 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
- application.xml配置文件
<!-- 开启spring的注解扫描功能 -->
<context:component-scan base-package="com.wenhua.spring"></context:component-scan>
<!-- 导入springMVC配置文件 -->
<import resource="springmvc.xml"/>
- web.xml配置文件
以前都是在通过main方法,读取.xml文件,从而加载配置文件。
springmvc是web工程是要部署在服务器上通过浏览器访问,在项目启动时,就需要将spring配置文件加载,
在web.xml配置文件中将会解析springmvc.xml以及application.xml文件,因为要向服务器部署。需要用到dispatcherServlet分发器0服务器启动前加载
<!-- 配置spring核心请求分发器 -->
<servlet>
<servlet-name>application</servlet-name>
<servlet-class>
org.springframework.web.servlet.dispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 找web-inf/classes/配置文件 -->
<param-value>classpath:application.xml</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<!-- 请求映射 -->
<servlet-mapping>
<servlet-name>application</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
设置springmvc的字符集编码,直接在web.xml配置文件中进行粘贴
<!-- springmvc配置字符集编码 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<!-- 在spring-web的jar包下filter-class第49行
@Nullable
private String encoding; -->
<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>
- Controller类
@Controller 注解可以实例化该类
@RequestMapping(path="/userCtr") 为该类或该方法指定路径(映射地址)
ModelAndView mv = new ModelAndView(“user/login”); 视图名就是将要访问页面的路径。通过springmvc.xml配置中的视图解析机制后路径为WEB-INF/jsp/user/login.jsp(请求转发)
package com.wenhua.spring.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping(path = "/userCtr")
public class UserController {
@RequestMapping(path = "/list")
public ModelAndView UserList() {
System.out.println("list列表");
ModelAndView mv = new ModelAndView("user/login");
mv.addobject("name", "文华");
return mv;
}
}
index.jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html >
<html>
<head>
<Meta charset="UTF-8">
<title>indexx</title>
</head>
<body>
<a href="userCtr/list">登录</a>
</body>
</html>
login.jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html >
<html>
<head>
<Meta charset="UTF-8">
<title>login</title>
</head>
<body>
${name }
登录成功
</body>
</html>
总结
在服务器部署项目时很多情况下有时候不成功,要检查是否加载为class文件,在服务器以及项目根目录下检查。
springMVC插件
- dispatcherServlet:前端控制器,在web.xml配置文件中配置
- HandlerMapping:处理器映射器,根据请求的url找到处理该请求的处理器Handler(即Controller),又返回给前端控制器dispatcherServlet
- HandlerAdapter:dispatcherServlet选择合适的HandlerAdapter(适配器),
- ModelAndView:dispatcherServlet取得了ModelAndView之后,l 需要将把逻辑视图名解析为具体的View,比如jsp视图,pdf视图等,这个解析过程由ViewResolver来完成。
- ViewResolver:ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术。
- View:就是要想用户展示的jsp,pdf等,最终dispatcherServlet将渲染的结果响应到客户端。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IzxCwmyK-1615994444236)(springMVC流程.jpg)]
参数接收
@RequestMapping(path="/userCtr") 为该类或该方法指定路径(映射地址),
@RequestMapping(value="/userCtr") 但是value也是可以进行配置路径的
@RequestMapping(path={"/userCtr","/user"}) path可以配置多个路径string[]
method=RequestMethod.Get/Post指定请求的方式
@GetMapping(path="/userCtr") 只能是get请求
@PostMapping(path="/userCtr") 只能是Post请求
- 注意在接收日期时一定要指定格式
@DateTimeFormat(pattern="yyyy-MM-dd")// 不然会报404错误
private Date birthday;
在Controller中接收jsp中的数据
// 通过 @RequestHeader获得请求头 @RequestParam 获得请求参数
public ModelAndView getRequset(
@RequestHeader("User-Agent") String userAgent,
@RequestHeader("Cookie") String cookie,
@RequestParam("account") String account,
@RequestParam("password") String password){ }
// 如果需要的参数名一致可直接获取(数据类型转换)
public ModelAndView getRequset(
String account,
String password,
Integer age){}
// 如果是一个实体,框架直接进行封装
public ModelAndView getRequset(User user){
// 注意要给日期格式
System.out.println(user);
return null;
}
// 实体外还有信息可直接通过名字获取
public ModelAndView getRequset(User user,String mark){}
// 通过HttpServletRequest,HttpServletResponse,HttpSession和JavaEE-servlet一样获取参数
public ModelAndView getRequset(
HttpServletRequest request,
HttpServletResponse response,
HttpSession session){
System.out.println(request.getParameter("account"));
System.out.println(request.getParameter("password"));
return null;
}
请求转发,重定向,访问静态资源
Maven07-2项目
在Controller中可以返回String类型,但是返回的仍然是路径,这个路径仍然会经过视图解析器。
这种一般用于跳转页面时使用。但这也是通过请求转发,可以通过request传递数据
@RequestMapping(value="/test")
public String vRedirection(){
return "user/login";
}
index.jsp
<form action="${path }/user/test" method="get">
账号<input type="text" name="account"/><br/>
密码<input type="password" name="password"/><br/>
<input type="submit" value="登录"/>
</form>
UserController.java
/**
* 重定向
* @param request
* @return
*/
@RequestMapping(value="/test")
public String vRedirection(HttpServletRequest request){
System.out.println(request.getParameter("account"));
// 在字符串前添加redirect:前缀,不会经过视图解析器,
// 以重定向的方式跳转到页面,地址会变化,不能访问web-inf目录下的文件
// "/"表示从项目的根目录查找,形成绝对路径
return "redirect:/Redirection.jsp";
}
/**
* 跳转页面
* @return
*/
@RequestMapping(value="/str")
public String vStrign(){
return "user/login";
}
Redirection.jsp
<a href="user/str">
这是重定向转发过来的,重定向不能访问web-inf文件夹下的jsp,<br/>
但是可以通过Controller跳转。<br/>
</a>
- 访问静态资源(jsp是动态文件)
在springmvc中的jsp页面上,不能访问静态资源文件(例如:图片,css,js……)
如果没有经过配置,访问静态文件是访问不到的,因为在web.xml配置文件中
springMvc /
配置地址为"/",所有的请求都会进入dispatcherServlet的映射地址,然后通过HandlerMapping去找对应的控制类。
在springmvc.xml配置文件中配置如下就OK了。默认serlvet进行处理。
<!-- 过滤静态资源文件 -->
<mvc:default-servlet-handler/>
ajax异步请求处理
请求转发,重定向都是同步请求。
- 引入jar包
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.1</version>
</dependency>
- 在jsp页面发起ajax请求
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html >
<html>
<head>
<Meta charset=UTF-8>
<title>index</title>
<script type="text/javascript" src="${path }/js/jquery-3.5.1.min.js"></script>
<script type="text/javascript">
$(function(){
$("#loginbtn").click(function(){
<%-- $.请求方式("发送路径" ,
"向Controller发送的数据" ,
接收返回值函数) --%>
$.get("${path}/user/list",$("#formId").serialize(),function(res){
console.log(res);
if(res != null){
alert("登录成功");
location.replace("${path}/user/str");
}else{
alert("登录失败");
}
})
})
})
</script>
</head>
<body>
<form id="formId">
账号<input type="text" name="account"/><br/>
密码<input type="password" name="password"/><br/>
<input type="button" value="登录" id="loginbtn"/>
</form>
</body>
</html>
- Controller控制类
在servlet中都是通过
PrintWriter out = response.getWriter();
来向jsp页面响应ajax请求,但是在springmvc中,不需要这样,而是通过
@ResponseBody
该注解的作用是将controller的方法返回都得对象通过适当的转换器转换为指定的格式后,写入到response对象的body区,通过用来向异步请求返回json数据,所以需要jar包
注意,在使用该注解之后,不会再走视图解析器,而是直接将数据写入到输入流中。
/**
* ajax异步请求返回普通数据类型
* @return
*/
@ResponseBody
@RequestMapping(value="/list")
public int userlist(){
try {
return 1;
} catch (Exception e) {
return 2;
}
}
/**
* ajax异步请求返回Account封装结果
* @param ac
* @return
*/
@ResponseBody
@RequestMapping(value="/list")
public Account userlist(Account ac){
try {
return ac;
} catch (Exception e) {
return null;
}
}
/**
* 跳转页面
* @return
*/
@RequestMapping(value="/str")
public String vStrign(){
return "user/login";
}
文件上传
Maven_ssm_db项目
- 导入需要的jar包
对提交的二进制文件进行解析
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency>
- 通过表单将本地文件提交到服务器
<div>
<form action="${path }/user/userImg" method="post" enctype="multipart/form-data">
头像<input type="file" name="userPhoto" accept=".png,.jpg"/>
<input type="submit" value="上传文件"/>
</form>
</div>
- 配置文件解析器,将apache组件解析后的结果给再次封装
<bean id=“multipartResolver” class**="org.springframework.web.multipart.commons.CommonsMultipartResolver">**
<property name=“defaultEncoding” value**="utf-8">property*>**
<property name=“maxUploadSize” value**="10485760">property*>**
能,但是只能用绝对地址,File filePath = new File(request.getcontextpath()+"\statics\imgs\"+user.getAccount()+oldPhotoName);这样是不行的,而且要注意在servlet中不能使用${}符号,只能通过绝对路径
File filePath = new File(“D:\Program Files (x86)\eclipse\WorkPlaces\Maven_ssm_db\src\main\webapp\statics\imgs\”+user.getAccount()+oldPhotoName);
注意存放的位置是服务器,可以通过服务器直接访问已经上传了的图片http://localhost:8888/Maven_ssm_db/statics/imgs/13240797843708908.png
在查看上传的照片时,不能通过D://……等一系列的路径,因为这会返回客户端后,使用客户端D://……路径,在不同的地方,含义不同。
文件下载
<a href="${path }/user/downloadImg">
<img alt="图片没有" src="${path }/statics/imgs/${user.newFileName}" title="点击下载">
</a>
/**
* 下载(文件)用户头像
* @param session
* @param file
* @return
* @throws IOException
*/
@GetMapping(path="/downloadImg")
public void DownLoadImg(
HttpServletResponse response,
HttpSession session){
// 包装一下,为了效率更高
BufferedInputStream bin = null;
bufferedoutputstream bout = null;
try {
// 获得当前用户
User user = (User) session.getAttribute("user");
// 获得要下载的文件
String downLoadFile = "D:\\Program Files (x86)\\eclipse\\WorkPlaces"
+ "\\Maven_ssm_db\\src\\main\\webapp\\statics\\imgs\\"+user.getNewFileName();
File file = new File(downLoadFile);
// 代表任意的二进制数据
response.setContentType("applicatoin/octet-stream");
// 设置将要下载文件的名称
response.setHeader("content-disposition", "attachment;filename="+
new String(user.getoldFileName().getBytes("utf-8"),"ISO-8859-1"));
//
FileInputStream in = new FileInputStream(file);
bin = new BufferedInputStream(in);
OutputStream out = response.getoutputStream();
bout = new bufferedoutputstream(out);
byte[] bs = new byte[1024];
int length = 0;
while((length = bin.read(bs))!= -1){
bout.write(bs, 0, length);
}
} catch (UnsupportedEncodingException e) {
// Todo Auto-generated catch block
e.printstacktrace();
} catch (FileNotFoundException e) {
// Todo Auto-generated catch block
e.printstacktrace();
} catch (IOException e) {
// Todo Auto-generated catch block
e.printstacktrace();
}finally{
try {
bin.close();
bout.flush();
bout.close();
} catch (IOException e) {
// Todo Auto-generated catch block
e.printstacktrace();
}
}
}
报错:在什么情况下,会报java.lang.IllegalStateException,其实一般情况下都是代码不严谨的问题造成的,下面给出了详细的解析,但是我的问题和下面的有点不同,但是是理解之后才明白自己代码问题的。
今天运行项目时出现的这个问题,java.lang.IllegalStateExceptio,第一次见到这个异常,
查询后
错误原因:该异常表示,当前对客户端的响应已经结束,不能在响应已经结束(或说消亡)后再向 客户端(实际上是缓冲区)输出任何内容。
具体分析:首先解释下flush(),我们知道在使用读写流的时候数据先被读入内存这个缓冲区中, 然后再写入文件,但是当数据读完时不代表数据已经写入文件完毕,因为可能还有 一部分仍未写入文件而留在内存中,这时调用flush()方法就会把缓冲区的数据强行 清空输出,因此flush()的作用就是保证缓存清空输出。 response是服务端对客户端请求的一个响应,其中封装了响应头、状态码、内容等, 服务端在把response提交到客户端之前,会向缓冲区内写入响应头和状态码,然后 将所有内容flush。这就标志着该次响应已经committed(提交)。对于当前页面中 已经committed(提交)的response,就不能再使用这个response向缓冲区写任何东西 (注:同一个页面中的response.XXX()是同一个response的不同方法,只要其中一个 已经导致了committed,那么其它类似方式的调用都会导致 IllegalStateException异常)。
能够导致响应已经committed的操作包括:forward, redirect, flushBuffer。
可以将项目从tomcat中先移除再部署上去,实在不行就把myeclipse中所有项目都清空一下,再从新部署上去。
-
其实我的问题是,在页面调用方法后,有String返回值,也就是说再次请求转发到当前页面,所以会报错,其实我的错误完整提示为java.lang.IllegalStateException: 当前响应已经调用了方法getoutputStream()
-
拦截器
创建拦截器类,并且实现handlerinterceptor接口,重写三个方法(也可只重写preHandle方法)
// 获得session并取得user对象
HttpSession session = request.getSession();
User user = (User) session.getAttribute("user");
if(user == null){
// 注意这里使用的是请求转发,可以直接访问到非WEB-INF文件下的文件
response.sendRedirect("index.jsp");
return false;
}else{
/*当请求到达控制器之前被执行
true--继续向下执行,到达下一个拦截器,或控制器
false--不会继续向下执行*/
return true;
}
在springmvc.xml配置文件中添加拦截器配置,在添加拦截器时头脑一定要清楚,注意preHandle方法只拦截从页面发往Controller的请求,不会拦截Controller中处理后的View
<!-- 请求拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置哪些请求被拦截 拦截器不会拦截jsp页面请求-->
<mvc:mapping path="/**"/>
<!-- 哪些请求不被拦截(放行) -->
<mvc:exclude-mapping path="/loginCon/toLogin"/>
<!-- 放行从index.jsp页面到main/login.jsp页面的请求 -->
<mvc:exclude-mapping path="/loginCon/chLogin"/>
<!-- 放行login.jsp页面登录的请求 -->
<mvc:exclude-mapping path="/statics/**"/>
<!-- 注入拦截器 -->
<bean id="isLogin" class="com.wenhua.spring.util.isLoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
法只拦截从页面发往Controller的请求,不会拦截Controller中处理后的View
<!-- 请求拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置哪些请求被拦截 拦截器不会拦截jsp页面请求-->
<mvc:mapping path="/**"/>
<!-- 哪些请求不被拦截(放行) -->
<mvc:exclude-mapping path="/loginCon/toLogin"/>
<!-- 放行从index.jsp页面到main/login.jsp页面的请求 -->
<mvc:exclude-mapping path="/loginCon/chLogin"/>
<!-- 放行login.jsp页面登录的请求 -->
<mvc:exclude-mapping path="/statics/**"/>
<!-- 注入拦截器 -->
<bean id="isLogin" class="com.wenhua.spring.util.isLoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。