1.新建一个web maven工程,使用web-app 骨架,如果我们有下载过骨架,那么在第三步Properties中添加键值对archetypeCatalog=internal
即使用本地仓库的骨架,避免创建maven工程时去网上下载,可以缩短时间。
2.添加依赖 spring-context,spring-webmvc,spring-web,servlet-api,jsp-api.
3.在web.xml中添加前端控制器:
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
4.配置tomcat服务器,在Deployment中添加我们当前项目,然后配置好热部署
5.重新创建index.jsp文件作为请求页面,并写入请求代码,创建控制器类,并写入请求的方法,和返回参数
6.创建spring配置文件,导入约束(除了基本的还需包含context和mvc),开启注解扫描,开启springmvc注解,配置Controller,RequestMapping注解在控制器类中
<!--开启自动扫描的包-->
<context:component-scan base-package="com.qjw"></context:component-scan>
<!--添加视图解析器-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--开启springmvc的注解-->
<mvc:annotation-driven></mvc:annotation-driven>
7.在web.xml中配置spring.xml文件的加载:
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置Servlet初始化参数,用来加载我们的spring配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.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>
8.在控制器中配置return参数,并在WEB-INF新建一个pages用来返回请求成功的页面
9.在spring中配置视图解析器
<!--添加视图解析器-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置前缀和后缀-->
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
10.在请求页面填入访问地址需要和控制器方法中的RequestMapping中的path或者value的路径或者值一致,一般我们在RequestMapping path或者value中配置了/,那么在请求页面就不用加/了。
11. RequestMapping的属性
1.请求参数(基本数据类型和字符串类型)
在jsp页面编写请求参数:
<h1><a href="param/paramtest1?username=aa&password=123">请求参数为基本数据类型和字符串</a></h1>
然后在Conroller类中:
@RequestMapping("/paramtest1")
//在要请求的方法中加入参数,参数名必须和请求的一致,即上面的username=aa必须和参数的username一致
public String paramTest(String username,int password)
{
System.out.println("请求成功,取得参数:"+username+"和"+password);
return "success";
}
2.请求参数(实体类(javaBean对象))
1.创建提交表单的页面:
<body>
<form action="javabean/saveaccount">
<!--name的值需和要请求的javabean的属性名一致-->
姓名:<input type="text" name="name"></br>
年龄:<input type="text" name="age"></br>
存款:<input type="text" name="account"></br>
<!--引用名.属性名-->
用户名:<input type="text" name="user.username"></br>
密码:<input type="text" name="user.password"></br>
<input type="submit" value="提交">
</form>
</body>
2.创建实体类或者javaBean类:
public class UserAccount {
private String name;
private int age;
private String account;
private User user;
....
public class User implements Serializable {
private String username;
private String password;
....
生成对应的get,set,toString方法,表单中的name属性要和javabean中的属性名一致,如果有引用类型的属性,那么采用引用名.属性名的方式,也需要一致
3.创建控制器类
@Controller
@RequestMapping("/javabean")
public class JavaBeanParamDemo {
@RequestMapping("/saveaccount")
//这里参数需要填表单所需要提交到哪个javabean
public String saveAccount(UserAccount useraccount)
{
System.out.println("请求成功:"+"\n"+useraccount);
return "success";
}
}
4.返回结果:
3.请求参数(集合类型)
1.写个表单用来提交数据:要注意的就是集合请求的方式
<form action="javabean/saveaccount">
<!--name的值需和要请求的javabean的属性名一致-->
姓名:<input type="text" name="name"></br>
年龄:<input type="text" name="age"></br>
存款:<input type="text" name="account"></br>
<!--集合引用名.对应类型的属性名-->
List用户名:<input type="text" name="myList[0].username"></br>
List密码:<input type="text" name="myList[0].password"></br>
Map用户名:<input type="text" name="myMap[0].username"></br>
Map密码:<input type="text" name="myMap[0].password"></br>
<input type="submit" value="提交">
</form>
2.修改javabean类,生成get,set,toString方法
public class UserAccount {
private String name;
private int age;
private String account;
private List<User> myList;
private Map<String,User> myMap;
....
3.控制类不变
@Controller
@RequestMapping("/param")
public class RequestParamDemo1 {
@RequestMapping("/paramtest1")
//在要请求的方法中加入参数,参数名必须和请求的一致,即上面的username=aa必须和参数的username一致
public String paramTest(String username,int password)
{
System.out.println("请求成功,取得参数:"+username+"和"+password);
return "success";
}
}
4.结果:
4.解决中文乱码(如果在传参时传表单输入中文,控制台输出乱码,注意,过滤器在web.xml中的位置要在Servlet前面)
解决办法:设置过滤器
在web.xml中
<!--中文乱码过滤器-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--初始化参数,指定encoding属性为utf-8-->
<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>/*
5.自定义类型转换器
描述:当我们进行参数传值的时候,大多数类型转换情况springmvc已经帮我们做完了,比如String->int,但是如果有它没有定义的转换类型,那么我们就要自己编写一个类型转换器
以Data类型为例:比如2019/10/21 springmvc能帮我们转换为日期类型,但是2019-10-21就不行了
1.写好提交页面
<form action="javabean/saveaccount">
姓名:<input type="text" name="name"><br>
年龄:<input type="text" name="age"><br>
生日:<input type="text" name="date"><br>
<input type="submit" value="提交">
</form>
2.修改javabean
public class UserAccount {
private String name;
private int age;
private Date date;
....
3.写自定义类型转换器类
//我们自定义的转换器必须实现springmvc的转换器接口Converter
public class DateConverter implements Converter<String,Date> {
@Override
public Date convert(String source) {
if (source==null){
System.out.println("日期输入为空!");
}
DateFormat date=new SimpleDateFormat("yyyy-mm-dd");
try {
return date.parse(source);
} catch (Exception e) {
throw new RuntimeException("类型转换出错!");
}
}
4.最后在spring.xml文件中,将我们自定义的类型转换器类加入到springmvc的类型转换器的set集合中
<!---配置自定义类型解析器-->
<bean id="converterService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<!--这是解析器里的一个属性-->
<property name="converters">
<set>
<!--转换器类路径-->
<bean class="com.qjw.util.DateConverter"></bean>
</set>
</property>
</bean>
<!--开启springmvc的注解-->
<!--将自定义的类型转换配置生效-->
<mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>
6.获取Servlet原生的api
1.jsp页面
<a href="javabean/servletapi">获取原生servletapi</a>
2.控制器
@RequestMapping("/servletapi")
//想要获取什么,参数就填什么
public String servletApi(HttpServletRequest request, HttpServletResponse response)
{
System.out.println("请求成功");
HttpSession session=request.getSession();
System.out.println(session);
ServletContext context=session.getServletContext();
System.out.println(context);
System.out.println(response);
return "success";
}
1.RequestParam注解
作用:把请求中的指定名称的参数传递给控制器中的形参赋值
属性
value:请求参数中的名称
required:请求参数中是否必须提供此参数,默认值是true,必须提供(这个参数是说这个参数为true的时候,那么请求参数中的name必须和RequestParam中的name或者value值一致,否则不能传值)
1.新建jsp文件
<body>
<h1><a href="annon/requestparam?name=你好">RequestParam注解</a></h1>
</body>
2.新建控制器类
@Controller
@RequestMapping("/annon")
public class AnnotationDemo {
@RequestMapping("/requestparam")
//可以发现RequestParam注解中的name和请求参数后面的name是一样的,然后@RequestParam将name值赋给了方法的参数usename
public String testRequestParam(@RequestParam(name="name")String usename)
{
System.out.println(usename);
return "success";
}
}
3.结果
2.RequestBody注解
作用:用于获取请求体的内容(注意:get方法不可以)
属性
required:是否必须有请求体,默认值是true
1.jsp页面
<form action="annon/requestbody" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="text" name="password"><br>
<input type="submit" value="提交">
</form>
2.控制器
//@RequestBody
@RequestMapping("/requestbody")
public String testRequestBody(@RequestBody String body)
{
System.out.println(body);
return "success";
}
注意,这里的参数必须要和表单中的参数不同,不然spring会进行默认参数匹配,我们要拿的是请求体
3.结果
3.PathVariable注解
作用:拥有绑定url中的占位符的。例如:url中有/delete/{id},{id}就是占位符
属性:
value:指定url中的占位符名称
Restful风格的URL:
请求路径一样,可以根据不同的请求方式去执行后台的不同方法
restful风格的URL优点
结构清晰
符合标准
易于理解
扩展方便
1.jsp页面
<!--这里只要路径直接/值就行了-->
<h1><a href="annon/pathvariable/10">PathVariable注解</a></h1>
2.控制器
/**
* 注解@PathVariable
* @param
* @return
*/
@RequestMapping("/pathvariable/{sid}")
public String testPathVariable(@PathVariable(name= "sid") String id){
//拿到sid的值=10赋值给id,然后打印出来
System.out.println(id);
return "success";
}
这里@PathVariable中的sid必须和 @RequestMapping("/pathvarivale/{sid}")
中的sid一致,且jsp页面必须传入一个值,如上的href="annon/pathvariable/10
3.结果
4. HiddentHttpMethodFilter注解
作用:
由于浏览器 form 表单只支持 GET 与 POST 请求,而 DELETE、PUT 等 method 并不支持,Spring3.0 添
加了一个过滤器,可以将浏览器请求改为指定的请求方式,发送给我们的控制器方法,使得支持 GET、POST、PUT
与 DELETE 请求。
使用方法:
第一步:在 web.xml 中配置该过滤器。
第二步:请求方式必须使用 post 请求。
第三步:按照要求提供_method 请求参数,该参数的取值就是我们需要的请求方式。
不常用,了解一下就可,因为RestFule中有个WebClient类能调用各种静态方法从而帮我们实现各种请求,或者用浏览器插件来模拟
5. RequestHeader注解
RequestHeader注解
作用:获取指定请求头的值
属性
value:请求头的名称
没多大用处
6.CookieValue注解
作用:用于获取指定cookie的名称的值
属性
value:cookie的名称
1.jsp页面
<h1><a href="annon/cookievalue">CookieValue注解</a></h1>
2.控制器
/**
* 注解@CookieValue
* @param
* @return
*/
@RequestMapping("/cookievalue")
public String testCookieValue(@CookieValue(value = "JSESSIONID") String cookievalue){
System.out.println(cookievalue);
return "success";
}
这里我们获取浏览器返回的JSESSIONID
,也就是jsessionid
结果:
7.ModelAttribute注解
作用
出现在方法上:表示当前方法会在控制器方法执行前线执行。
出现在参数上:获取指定的数据给参数赋值。
应用场景
当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
例如
我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数
据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。
1.jsp页面
<form action="annon/modelattribute" >
用户名:<input type="text" name="name"><br>
年龄:<input type="text" name="age"><br>
<input type="submit" value="提交">
</form>
2.javabean生成get,set,toString方法
public class UserAccount implements Serializable{
private String name;
private int age;
private Date date;
....
3.控制器
/**
* 注解@ModelAttribute
* @param
* @return
*/
@RequestMapping("/modelattribute")
public String testmodelAttribute(UserAccount userAccount){
System.out.println(userAccount);
return "success";
}
//这里name用于取得页面传入的参数name的值然后从数据库根据name查询取出date
@ModelAttribute
public UserAccount addAttribute(String name)
{
//模拟从数据库查询日期然后给对象赋值
UserAccount userAccount=new UserAccount();
userAccount.setDate(new Date());
return userAccount;
}
4.结果
分析:这是@ModelAttribute
第一种有返回值的作用于方法的方式,因为有了@ModelAttribute
注解,被注解的方法优先于请求的方法执行,所以我们能先获取到name,查询之后给UserAccount赋值然后返回该对象执行请求的方法testmodelAttribute,然后请求页面传的参数也赋值到了javabean上,最后得到该对象
第二种方法,没有返回值类型
只改变控制器中的方法
1.控制器
/**
* 注解@ModelAttribute
* @param
* @return
*/
@RequestMapping("/modelattribute")
public String testmodelAttribute(@ModelAttribute("abc") UserAccount userAccount){
System.out.println(userAccount);
return "success";
}
//这里name用于取得页面传入的参数name的值然后从数据库根据name查询取出date
@ModelAttribute
public void addAttribute(String name, Map<String,UserAccount> map)
{
//模拟从数据库查询日期然后给对象赋值
UserAccount userAccount=new UserAccount();
userAccount.setDate(new Date());
map.put("abc",userAccount);
}
分析:这种方法在于将根据name到数据库查询到date,将该date存入到一个map集合中,然后在请求方法参数中使用@ModelAttribute注解将值abc赋给userAccount对象。
8.SessionAttributes注解
作用:用于多次执行控制器方法间的参数共享,进行存储,读取数据,且这个注解只能作用于类上.
用于将数据存进Request域中,比如在请求页面将数据存入request域,然后在控制台执行跳转到成功页面,再从成功页面取的存入的值。
那为什么不用前面的使用原生的servlet API呢?因为这样会造成程序耦合性过高,比如编译期必须提供servletAPI才能编译成功,所以springMVC为
我们提供了一个接口Model,这个Model有个实现类ModelMap,而这个ModelMap又继承与ListHashMap,所以我们就将要存入的值相当于存入到一个map中
那么问题来了,怎么存呢?
1.存储数据(后台将数据存储到Request域中)
请求jsp页面:
<h1><a href="annon/sessionattributes">SessionAttributes注解</a></h1>
2.控制器
@RequestMapping("/sessionattributes")
//Model用于存入数据
public String testSessionAttributes(Model model)
{
System.out.println("请求成功!");
model.addAttribute("name","你好");
return "success";
}
3.结果页面,如果不能显示,那么在<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false"%>
加上isELIgnored="false"
即可加载el表达式
<body>
${
requestScope}
</body>
如果我们加上SessionAttributes注解,即在控制类上加上该注解
@Controller
@RequestMapping("/annon")
@SessionAttributes(value = {
"name"})//如果加上这个注解,那么相当于把数据存入到了Session域中,注意,前面演示的例子数据只存进了Request域中
public class AnnotationDemo {
那么我们在结果页面:
<body>
<!--Request域中也可以直接${
name}取值-->
Request域中取出的值: ${
requestScope.name}<br>
Session域中取出的值: ${
sessionScope}
</body>
结果:
如果存到Session域中了,我们怎么取值?和删除值呢?
控制器:
/**
* 用于从后台取出Session中的值,用ModelMap来获取值
*/
@RequestMapping("/getsessionattributes")
public String testGetSessionAttributes(ModelMap modelMap)
{
System.out.println("取出成功!");
String msg=(String)modelMap.get("name");
System.out.println(msg);
return "success";
}
/**
* 从后台删除Session中的值,参数调用方法就是删除
*/
@RequestMapping("/delsessionattributes")
public String testDelSessionAttributes(SessionStatus status)
{
System.out.println("删除成功!");
status.setComplete();
return "success";
}
依次点击
成功页面
你会发现第一个是设置值,第二个是获取值,第三个是删除值,注意第三个删除的只是Session域中的值,Request中的并没有被删除
结果图:
设置:
获取:
删除:
如果你疑惑为什么设置和获取是一样的?那么我和你说我们第一个页面只是为了知道我们设置成功而已
这里说的返回值是控制器的方法,也就是发送请求的页面需要请求的映射方法
1.返回字符串类型
描述:请求页面给我们发来一个请求,我们根据请求的内容到数据库查询然后将查询结果存到Model中,最后在结果页面从Request域中根据key获取存入的字符串。
1.请求页面
<body>
<h1><a href="user/testresponsestring">请求服务器</a></h1>
</body>
2.javabean
public class User implements Serializable {
private String name;
private int age;
private String sex;
....
3.控制器
@Controller
@RequestMapping("/user")
public class TestResponseString {
@RequestMapping("/testresponsestring")
public String testResponseString(Model model)
{
//这里模拟一个从数据库查询返回的对象,然后存入Model中
User user=new User();
user.setName("小明");
user.setAge(18);
user.setSex("男");
System.out.println(user);
model.addAttribute("user",user);
return "success";
}
}
4.结果页面
<body>
<!--跳转页面从Request域中根据key取值-->
<h2>请求成功!</h2><br>
<h1>姓名:${
user.name} 年龄:${
user.age} 性别:${
user.sex}</h1>
</body>
2.返回值是void类型
1.jsp页面
<h1><a href="user/testresponsevoid">请求服务器Void</a></h1>
2.控制器
@RequestMapping("/testresponsevoid")
public void testResponseVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//方法一:用请求转发到成功页面
//request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
//方法二:重定向(重定向不能访问WEB-INF下的文件,所以我们访问webapp下的index.jsp)
//response.sendRedirect(request.getContextPath()+"/index.jsp");
//方法三:直接响应
//设置中文乱码
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().print("你好");
}
3.返回值是ModelView对象
1.jsp页面
<h1><a href="user/testResponseModelAndView">请求服务器ModelAndView</a></h1>
2.控制器
@RequestMapping("/testResponseModelAndView")
public ModelAndView testResponseModelAndView() {
//创建一个springmvc给我们提供的ModelAndView对象
ModelAndView mv = new ModelAndView();
//这里模拟一个从数据库查询返回的对象,然后存入Model中
User user = new User();
user.setName("小明");
user.setAge(18);
user.setSex("男");
System.out.println(user);
mv.addObject("user", user);
mv.setViewName("success");
return mv;
}
这里注意,返回值是ModelAndView,将对象加入到ModelAndView用addObject(),跳转页面用setName().
3.用关键字来表示请求转发和重定向
不常用,但是需了解
1.控制器
//请求转发和重定向使用关键字的方式
@RequestMapping("/testForwardAndRedirect")
public String testForwordAndRedirect() {
//请求转发方式
//return "forward:/WEB-INF/pages/success.jsp";
//重定向方式,注意只能请求项目根目录下的文件
return "redirect:/index.jsp";
}
这样就ok了
4.ResponeBody响应json数据(示例在5)
准备工作:
1.在webapp下创建js文件,然后引入jquery文件(注意是webapp下创建,不是WEB-INF)
2.新建respone.jsp请求页面
1.请求页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script src="js/jquery.min.js"></script>
<script>
$(function () {
$("#btn").click(function () {
alert("你好");
});
});
</script>
</head>
<body>
<button id="btn">发送Ajax请求</button>
</body>
</html>
2.因为我们引入了jquery文件,但是我们配置的前端控制器DispatcherServlet会拦截所有请求,所以我们需要在spring.xml文件中配置:
<!--配置前端控制器哪些静态资源不会被拦截,mapping和映射地址有关,location和服务器请求资源有关-->
<mvc:resources location="/js/" mapping="/js/**"/>
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/amages/" mapping="/amages/**"/>
这样当我们点击button时,会弹出一个响应
5.发送AJAX请求
准备工作:
1.json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包
有了这个jackson的jar包,当我们客户端向服务器发送json数据的时候,如果发送的数据的key和我们的控制器方法参数对象的属性相同,那么就会自动把数据给我们封装到javabean对象中
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
2.编写AJAX请求页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script src="js/jquery.min.js"></script>
<script>
$(function () {
$("#btn").click(function () {
//这是原始的发送Ajax请求,直接$.get(),$.post()底层其实都是调用的这个
$.ajax({
//请求控制器的地址映射
url:"user/testAjaxRequest",
//设置客户端向服务端发送的数据类型和编码
contentType:"application/json;charset=utf-8",
//客户端发送的数据
data:'{"name":"小红","age":"18","sex":"女"}',
//设置服务端返回的数据类型为json
dataType:"json",
//设置请求方式
type:"post",
//返回成功接收数据的函数,data为封装的服务器返回的数据,这里是json
success:function (data) {
alert(data.name+data.age+data.sex);
}
});
});
});
</script>
</head>
<body>
<button id="btn">发送Ajax请求</button>
</body>
</html>
3.控制器类
//RequestBody用于将服务器请求的json数据转换成我们的javabean(这里是User)对象
// ResponseBody用于将我们的javabean(这里是User)对象转换成Json数据返回
@RequestMapping("/testAjaxRequest")
public @ResponseBody User testAjaxRequest(@RequestBody User user)
{
//打印看看有没有收到客户端发送过来的数据
System.out.println(user);
//模拟客户端请求,并去数据库查找返回数据,把年龄改为22传回客户端
user.setAge(22);
return user;
}
1.springmvc文件上传
1.准备工作
文件上传的必要前提:
multipart/form-data
(默认值是:application/x-www-form-urlencoded),enctype:是表单请求正文的类型
-----------------------------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--
2.借助第三方组件实现上传
使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:commons-fileupload 和
commons-io。commons-io 不属于文件上传组件的开发 jar 文件,但Commons-fileupload 组件从 1.1 版本开始,它
工作时需要 commons-io 包的支持。
3.使用springmvc进行文件上传必须在spring.xml配置springmvc给我们提供的文件解析器:
<!--这里的id值必须为multipartResolver,然后我们指定了上传文件字节大小最大为10M,也就是10*1024*1024=10485760-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"></property>
</bean>
4.编写上传页面
<body>
<h2><a href="user/fileUpLoad01">请求服务器!</a></h2>
<form action="user/fileUpLoad02" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br/>
<input type="submit" value="提交"/>
</form>
</body>
5.控制器类
//需要传入参数HttpServletRequest和MultipartFile,且这里MultipartFile的引用upload必须和jsp页面文件标签的name一致
@RequestMapping("/fileUpLoad02")
public String fileUpLoadDemo2(HttpServletRequest request, MultipartFile upload) throws Exception
{
//获取要上传文件的位置
String path=request.getSession().getServletContext().getRealPath("/upload/");
File file=new File(path);
if (!file.exists())
{
file.mkdir();
}
//获取上传文件的名称
String fileName=upload.getOriginalFilename();
//把文件名称设置为唯一ID值
String uuid= UUID.randomUUID().toString().replace("-","");
fileName=uuid+"_"+fileName;
//上传文件
upload.transferTo(new File(path,fileName));
return "success";
}
2.不同服务器之间的文件上传
简介:在实际开发中,我们会有很多处理不同功能的服务器。例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理大并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器。
(注意:此处说的不是服务器集群)
准备工作:
为了实现跨服务器,sun公司为我们提供了2个jar包,需要导入依赖(是在我们的应用服务器导入)
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
创建一个module(模块),选择web-app骨架,然后选none,输入项目名,创建好项目之后
配置好tomcat服务器,其中1,2,3地方需要和我们的应用服务器(也就是图片上传的那个工程)不同,选择我们当前项目配置好就ok了
启动第二个服务器,弹出helloword页面说明服务器启动成功
1.准备就绪,编写jsp页面
跨服务器上传文件:
<form action="user/fileUpLoad03" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br/>
<input type="submit" value="提交"/>
</form>
2.控制器类
//跨服务器上传文件
@RequestMapping("/fileUpLoad03")
public String fileUpLoadDemo3(MultipartFile upload) throws Exception
{
System.out.println("请求成功!");
//获取文件要上传的服务器路径,然后加上文件夹upload路径后面加个/方便后面不用填写,这里注意
//我们需要手动去文件服务器项目下(磁盘下)创建一个uploads文件
//这边的path地址是第二个Tomcat配置中的URL加上uploads
String path="http://localhost:9090/fileuploadserver/uploads/";
//获取上传文件的名称
String fileName=upload.getOriginalFilename();
//把文件名称设置为唯一ID值
String uuid= UUID.randomUUID().toString().replace("-","");
fileName=uuid+"_"+fileName;
//创建客户端对象
Client client=Client.create();
//和图片服务器进行连接,这里path后面就不用再加"/"了因为第一步我们获取路径的后面加了返回一个WebResource对象
WebResource webResource=client.resource(path+fileName);
//上传文件
webResource.put(upload.getBytes());
return "success";
}
然后上传文件
最后,在启动的时候会出现各种错误比如403,405之类的,出现这些问题有2种解决办法
1.打开你Tomcat安装目录->conf->web.xml
加入
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
原因是因为Tomcat服务器默认不允许我们跨服务器上传文件,设置为false就好了
如果出现其他问题,请注意图片的名字,不要带中文,如果是中文要另外进行配置(请自行百度)
如果还出现错误,检查磁盘工程的目录下有没有uploads这个文件夹,或者idea文件服务器项目webapp下新建一个uploads文件夹,最后
改完最好重启项目和服务器吧
1.拦截器
Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
用户可以自己定义一些拦截器来实现特定的功能。
谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺
序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,但
是也有区别,接下来我们就来说说他们的区别:
过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。
拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。
过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。
拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦
截的。
它也是 AOP 思想的具体应用。
我们要想自定义拦截器, 要求必须实现:HandlerInterceptor 接口。
步骤
1.编写请求jsp
<body>
<a href="user/test">发送请求</a>
</body>
2.控制器类
@Controller
@RequestMapping("/user")
public class TestController {
@RequestMapping("/test")
public String TestDemo() throws Exception
{
System.out.println("请求成功");
return "success";
}
}
3.拦截器类
//必须要继承HandlerInterceptor
public class TestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器执行");
//返回true表示执行完该方法继续执行控制器中的方法
//还可以在return直接进行请求转发等操作
//request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return true;
}
}
4.spring.xml
<!--配置多个拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--拦截器需要拦截的映射,和控制器中的RequestMapping有关,如果要拦截所有控制器的方法用"/**"-->
<mvc:mapping path="/user/*"/>
<!--配置拦截器类-->
<bean class="com.qjw.interceptor.TestInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
2.异常处理
在springmvc中异常是可以网上抛的
1.jsp页面
<body>
<a href="user/test">发送请求</a>
</body>
2.控制器类
@RequestMapping("/test")
public String TestDemo() throws Exception
{
System.out.println("请求成功");
try {
//模拟一个异常
int a = 10 / 0;
}catch (Exception e)
{
e.printStackTrace();
throw new EntityException("查询异常");
}
return "success";
}
3.创建异常类
public class EntityException extends Exception{
private String message;
public EntityException(String message) {
this.message = message;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
4.创建异常控制器类
//需要继承HandlerExceptionResolver
public class TestHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
EntityException e=null;
if (ex instanceof EntityException)
{
e=(EntityException)ex;
}else
{
e=new EntityException("系统正在维护");
}
//然后再用ModelAndView封装并跳转到友好的错误页面
ModelAndView mv=new ModelAndView();
mv.addObject("errorMsg",e.getMessage());
mv.setViewName("error");
return mv;
}
}