Springmvc
Springmvc 简介
Springmvc 实战
这边的学习方式,主要是使用了how2j这一网站中的教程以及代码进行一番学习。
Hello World!
首先,建立一个java web 动态项目。
接下来,我们需要编写一个web.xml 配置文件来配置一个默认Servlet:
下面的代码创建了一个类名为org.springframework.web.servlet.DispatcherServlet
,servlet名为springmvc
,映射的url 为/
,即默认Servlet,当其他的Servlet无法匹配成功的时候,传给其处理。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
接下来,编写一个Servlet配置文件:
下面的Servlet 中编写了一个mapping映射属性,将/index
这么一个url分配给了indexController
这个控制器。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="simpleUrlHandlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/index">indexController</prop>
</props>
</property>
</bean>
<bean id="indexController" class="controller.IndexController"></bean>
</beans>
最后,我们编写一个控制器类:
package controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class IndexController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView("index.jsp");
mav.addObject("message", "Hello Spring MVC");
return mav;
}
}
那么下面是:
前端一个简单的jsp文件,用来el表达式获取上面控制器传入的message。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isELIgnored="false"%>
<h1>${message}</h1>
运行结果如下:
实现流程:
首先,我们用户访问了一个/Springmvc项目下的/index路径,
那么访问默认传给了DispatcherServlet,然后根据配置,Servlet将/index路径请求转发给IndexController 控制器去处理,控制器将其转到前端的 index.jsp 页面上,并传递我们的消息。
视图定位
通过视图定位的功能,我们能够更方便配置我们的网页路径。
实现这样的功能关键的一步:就是给servlet容器中注入一个视图解析器。
添加两个属性,前缀、后缀。
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/" />
<property name="suffix" value=".jsp" />
</bean>
然后将前端文件移动到 /WEB-INF/page/ 目录下。
再将url:index.jsp改为index
表单提交
首先,我们先添加一个Product 实体类:
package pojo;
public class Product {
private int id;
private String name;
private float price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
}
接着,我们实现一个简单的表单提交页面:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="java.util.*" isELIgnored="false"%>
<form action="addProduct">
产品名称 :<input type="text" name="name" value=""><br />
产品价格: <input type="text" name="price" value=""><br />
<input type="submit" value="增加商品">
</form>
下面是一个产品添加的控制器,映射提交的URL:addProduct
。
其中name和price都是直接注入到product中的。
这里仅仅将其属性发送到视图网页中展示,实际使用中,我们需要将其添加到数据库。
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import pojo.Product;
@Controller
public class ProductController {
@RequestMapping("/addProduct")
public ModelAndView add(Product product) throws Exception {
ModelAndView mav = new ModelAndView("showProduct");
return mav;
}
}
下面是一个简单的产品展示页面:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isELIgnored="false"%>
产品名称: ${product.name}<br>
产品价格: ${product.price}
表单提交后,运行结果如下:
客户端跳转
在前面的例子中,如index 跳转到index.jsp 或者 /addProduct 跳转到展示页面,都是服务端跳转
首先,在indexControllor中添加/jump 对应的函数。
重定向到 /index 。
@RequestMapping("/jump")
public ModelAndView jump() {
ModelAndView mav = new ModelAndView("redirect:/index");
return mav;
}
会话Session存储
这里Session 直接使用函数参数即可获得。
简单来说,就是获取session中的count,然后令其自增, 如果获取不到,则从0初始化。所以这个check能在一次会话中,简单的计数点击网页的次数。
@RequestMapping("/check")
public ModelAndView check(HttpSession session) {
Integer i = (Integer) session.getAttribute("count");
if (i == null)
i = 0;
i++;
session.setAttribute("count", i);
ModelAndView mav = new ModelAndView("check");
return mav;
}
处理中文
在对于我们使用Springmvc 提交表单的时候,有时候会遇到中文编码格式的问题。
于是,我们使用filiter过滤器来处理编码格式的问题。
这是一个简单的字符编码过滤器,指定了编码格式为utf-8。
<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>
修改表单提交的编码格式:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="java.util.*" isELIgnored="false"%>
<form action="addProduct" method="post">
产品名称 :<input type="text" name="name" value=""><br />
产品价格: <input type="text" name="price" value=""><br />
<input type="submit" value="增加商品">
</form>
文件上传
首先,我们得配置一下,使得默认的Servlet能接受图片资源的处理。
因为前面我们把Url:\
提交给Springmvc 这一个Servlet处理,但它并没有重写处理图片这样的静态资源的功能。所以需要一下的配置:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
配置如下对象,提供对文件上传的支持:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
下面,写一个简单的上传前端页面:
其中form 表单属性method="post"
和 enctype="multipart/form-data"
是缺一不可。
<input type="file" name="image" accept="image/*" />
中accept 表示只可以接受图片文件。name是获取图片用到的名字。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="java.util.*" isELIgnored="false"%>
<form action="uploadImage" method="post" enctype="multipart/form-data">
选择图片:<input type="file" name="image" accept="image/*" /> <br>
<input type="submit" value="上传">
</form>
下面是一个上传文件对应的类:
package pojo;
import org.springframework.web.multipart.MultipartFile;
public class UploadedImageFile {
MultipartFile image;
public MultipartFile getImage() {
return image;
}
public void setImage(MultipartFile image) {
this.image = image;
}
}
下面是一个上传事件处理的类:
package controller;
import java.io.File;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.xwork.RandomStringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import pojo.UploadedImageFile;
@Controller
public class UploadController {
@RequestMapping("/uploadImage")
public ModelAndView upload(HttpServletRequest request, UploadedImageFile file)
throws IllegalStateException, IOException {
String name = RandomStringUtils.randomAlphanumeric(10);
String newFileName = name + ".jpg";
File newFile = new File(request.getServletContext().getRealPath("/image"), newFileName);
newFile.getParentFile().mkdirs();
file.getImage().transferTo(newFile);
ModelAndView mav = new ModelAndView("showUploadedFile");
mav.addObject("imageName", newFileName);
return mav;
}
}
最后是一个简单的显示上传图片的网页:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isELIgnored="false"%>
<img src="image/${imageName}"/>
拦截器
Springmvc 的拦截器,就是在controllor控制器执行前、执行后但视图执行前,和视图执行后添加一定的处理代码。
这个简单来说有点像以前Python Django框架中的中间件。就是在处理的流程补充一些处理。
首先我们定义一下我们的拦截器类:
package interceptor;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class IndexInterceptor extends HandlerInterceptorAdapter {
/**
* 在业务处理器处理请求之前被调用
* 如果返回false
* 从当前的拦截器往回执行所有拦截器的afterCompletion(),再退出拦截器链
* 如果返回true
* 执行下一个拦截器,直到所有的拦截器都执行完毕
* 再执行被拦截的Controller
* 然后进入拦截器链,
* 从最后一个拦截器往回执行所有的postHandle()
* 接着再从最后一个拦截器往回执行所有的afterCompletion()
*/
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle(), 在访问Controller之前被调用");
return true;
}
/**
* 在业务处理器处理请求执行完成后,生成视图之前执行的动作
* 可在modelAndView中加入数据,比如当前时间
*/
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle(), 在访问Controller之后,访问视图之前被调用,这里可以注入一个时间到modelAndView中,用于后续视图显示");
modelAndView.addObject("date","由拦截器生成的时间:" + new Date());
}
/**
* 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等
*
* 当有拦截器抛出异常时,会从当前拦截器往回执行所有的拦截器的afterCompletion()
*/
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion(), 在访问视图之后被调用");
}
}
下面对我们的拦截器进行一个简单的配置:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/index"/>
<!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 -->
<bean class="interceptor.IndexInterceptor"/>
</mvc:interceptor>
<!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法 -->
</mvc:interceptors>
然后测试的结果如下:
参考
- 主要学习资料:how2java中的Springmvc教程