说明:
MVC:替换Servlet,拦截请求与控制页面跳转,类似于Struts框架。
导入依赖jar包:spring-web-x.x.x.RELEASE、spring-webmvc-x.x.x.RELEASE、spring-core-x.x.x.RELEASE.jar、spring-context-x.x.x.RELEASE.jar、spring-beans-x.x.x.RELEASE.jar、spring-aop-x.x.x.RELEASE.jar
通用依赖jar包:commons-logging-x.x.jar、log4j-x.x.xx.jar
一、创建"请求处理类(类似Servlet),处理带参请求,带参页面跳转等:
1.使用@Controller配置当前类为页面求处理类:
(1)路径无子目录方式:
@Controller
public class LoginControl {
...
}
(2)路径有子目录方式:
@Controller
@RequestMapping("dir1") //给路径加上子目录,访问路径为:http://.../根目录/dir1/login.acion
//@RequestMapping(value = "dir1") //同上
public class LoginControl {
...
}
(3)限制请求方式(GET、POST等):
@Controller
@RequestMapping(method = { RequestMethod.GET, RequestMethod.POST }) // 限制请求方式为GET或POST
//@RequestMapping(method = RequestMethod.POST ) // 同上
public class LoginControl {
...
}
2.使用@RequestMapping映射路径<->方法,在LoginControl类中增加方法:
(1)无传参方式:
@RequestMapping("login") //拦截后缀为login.action的请求,如http://.../根目录/login.action
//@RequestMapping(value={"login","login2"}) //同上,支持多个路径
public String login() {
...
}
(2)基本类型传参方式:
参数类型说明:整型、字符串、单精度、双精度、布尔型
get方式访问地址:http://.../根目录/login.action?mobile=13000
@RequestMapping("login")
public ModelAndView login(@RequestParam("mobile")String phone) { //@RequestParam()表示取出mobile参数的值,赋值给phone
//public ModelAndView login(@RequestParam(value = "mobile", required = true, defaultValue = "123") String phone) { //同上,required表示必传,defaultValue为默认值
...
}
(3)对象类型传参方式,传的参数名称必须与对象属性名一样,属性必须有set方法:
get方式访问地址:http://.../根目录/login.action?phone=13000
传参方式:属性名,如phone=13000
@RequestMapping("login")
public String login(User user) {
...
}
User.java(对象类型):
public class User {
public String phone;
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
(4)包装对象类型传参方式:
get方式访问地址:http://192.168.1.2:8080/根目录/login.action?user.phone=13000
传参方式:类属性名.基本属性名,如user.phone=13000
@RequestMapping("login")
public String login(UserWrap userWrap) {
...
}
UserWrap.java(包装对象类型):
public class UserWrap {
public User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
(5)数组类型传参方式:
页面表单请求:
<form action="/根目录/login.action" method="post">
<input type="text" name="keys">
<input type="text" name="keys">
<input type="submit">
</form>
接收请求:
@RequestMapping("login")
public String login(int[] keys) {
...
}
(6)List类型传参方式(要和对象类型组合使用):
页面表单请求:
<form action="/TestWeb/login.action" method="post">
<input type="text" name="keys"> <!-- 此keys对应User的keys属性 -->
<input type="text" name="keys"> <!-- 此keys对应User的keys属性 -->
<input type="submit">
</form>
接收请求:
@RequestMapping("login")
public String login(User user, Model model) {
...
}
User.java:
public class User {
public List<String> keys; //此keys属性对应页面表单的name="keys"
public List<String> getKeys() {
return keys;
}
public void setKeys(List<String> keys) {
this.keys = keys;
}
}
3.控制页面跳转:
(1)return ModelAndView方式:
@RequestMapping("login")
public ModelAndView login() {
ModelAndView mav = new ModelAndView();
//传参给要跳转的页面
mav.addObject("key", "value");
//跳转到指定页(需要配置跳转路径前/后缀):/WEB-INF/jsp/LoginSuccess.jsp
mav.setViewName("LoginSuccess");
return mav;
}
(2)return 字符串方式:
@RequestMapping("login")
public String login(Model model) {
//传参给要跳转的页面
model.addAttribute("key", "value");
//跳转到指定页(需要配置跳转路径前/后缀):/WEB-INF/jsp/LoginSuccess.jsp
return "LoginSuccess";
//return "forward:home.html";//转发,不能访问WEB-INF下的页面
//return "redirect:home.html";//重定向,不能访问WEB-INF下的页面
}
(3)Servlet方式:
@RequestMapping("login")
public void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取传参
String value = req.getParameter("key");
System.out.println(value);
// 传参给要跳转的页面
req.setAttribute("key2", "value2");
// 跳转到指定页(转发)
req.getRequestDispatcher("/WEB-INF/jsp/LoginSuccess.jsp").forward(req, resp);
}
二、配置"请求处理类",在spring-mvc.xml中配置包扫描(src目录下):
1.配置映射器+适配器:
方法一:
<?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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 配置包扫描,实例化LoginControl.java -->
<context:component-scan base-package="com.yyh.hkw.control"/>
<!-- 配置映射器,处理请求路径到方法的调用 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!-- 配置适配器,处理请求路径到方法的调用 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
</beans>
方法二:
<beans>
<!-- 配置包扫描,实例化LoginControl.java -->
<context:component-scan base-package="com.yyh.hkw.control"/>
<!-- 配置注解驱动,等同于配置映射器+适配器,处理请求路径到方法的调用-->
<mvc:annotation-driven />
</beans>
2.在<beans>节点中,配置跳转路径前/后缀(代码处路径少写前后缀):
<!-- 配置路径前/后缀,在跳转时可省略前/后缀 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
三、配置请求拦截与编码过滤器(类似servlet配置),在web.xml中:
1.配置拦截*.action后缀的请求路径,在<web-app>节点中加入:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
metadata-complete="true" version="4.0">
<welcome-file-list>
<welcome-file>home.html</welcome-file>
</welcome-file-list>
<!-- 配置拦截*.action后缀的请求路径 -->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 加载spring-mvc.xml文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
2.配置编码过滤器(处理乱码),在<web-app>节点中加入:
<!-- 编码过滤器(处理乱码) -->
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
四、日期转换器(将表单字符串转换为Date类型传参给请求控制类):
1.创建自定义日期转换类,实现org.springframework.core.convert.converter.Converter:
//日期转换器
public class DateConvert implements Converter<String, Date> {
@Override
public Date convert(String srcDate) {
try {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH");
return format.parse(srcDate);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
2.配置自定义日期转换类,在spring-mvc.xml文件<beans>节点内:
<!-- 自定义日期转换类,refDateConvert为自定义id值 -->
<bean id="refDateConvert" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<!-- 自定义的日期转换类 -->
<bean class="com.yyh.hkw.domain.DateConvert"/>
</set>
</property>
</bean>
<!-- 配置注解驱动,等同于配置映射器+适配器,处理请求路径到方法的调用,refDateConvert为自定义日期转换类-->
<mvc:annotation-driven conversion-service="refDateConvert"/>
3.传递日期类型的参数,实现自动转换:
(1)User.java:
public class User {
public Date date;//对应页面表单name="date"
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
(2)LoginControl.java:
@RequestMapping("login")
public String login(User user, Model model) {
...
}
(3)页面表单请求:
<form action="/TestWeb/login.action" method="post">
<input type="text" name="date"> <!-- name="date"对应User.date属性 -->
<input type="submit">
</form>
五、全局异常处理:
1.自定义HandlerExceptionResolver实现类,处理全局异常:
//全局异常处理
public class GlobalException implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse resp, Object arg2, Exception e) {
ModelAndView mav = new ModelAndView();
//跳到错误页(需要配置跳转路径前/后缀):/WEB-INF/jsp/error.jsp
mav.setViewName("error");
return mav;
}
}
2.配置全局异常处理类,在spring-mvc.xml的<beans>标签中:
<beans ...>
...
<!-- 配置全局异常处理类 -->
<bean class="com.yyh.hkw.control.GlobalException"/>
</beans>
六、配置图片访问路径(Web Modules):
1.代码方式:
打开eclipse中Servers/Tomcat v9.0 Server at localhost-config/server.xml文件,在Host节点中插入如下代码:
<Context docBase="D:\JavaEEDevelop\apache-tomcat-9\images" path="/images" reloadable="true"/>
2.菜单操作方式:
(1)在eclipse中找到Servers控制台,选中"Tomcat v9.0 Server at localhost"。在新打开的面板中,选中Modules。在右侧点击"Add External Web Module...",如图所示:
(2)在"Add Web Module"弹出框中,Document base选中本地硬盘某个目录"D:\JavaEEDevelop\apache-tomcat-9\images",在Path中输入访问路径"/images",如图所示:
3.访问路径:
http://.../images/icon1.png
七、图片上传处理:
依赖jar包:commons-fileupload-x.x.jar、commons-io-x.x.jar
1.配置图片上传处理器:
<!-- 配置图片上传处理类,id值必须为multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="1048576" /> <!-- 最大字节数,单位为B,此处为1*1024*1024 -->
</bean>
2.配置文件上传处理类:
//@Controller配置当前类为页面求处理类
@Controller
public class UploadControl {
@RequestMapping("upload")
public String upload(HttpServletRequest req, MultipartFile imgFile) { // MultipartFile表示文件类型,imgName和页面表单<input type="file" name="imgFile" />对应
//获取上传的文件原名称
String fileName = imgFile.getOriginalFilename();
//得到文件存储目录
String dir = req.getSession().getServletContext().getRealPath("/WEB-INF/file");
File file = new File(dir, fileName);
try {
//将上传的文件写入指定路径
imgFile.transferTo(file);
} catch (IllegalStateException | IOException e) {
e.printStackTrace();
}
return "UploadSuccess"; //跳到上传成功页
}
}
3.Html表单代码:
<!-- multipart/form-data表示文件流 -->
<form action="/TestWeb/upload.action" enctype="multipart/form-data" method="post">
<input type="file" name="imgFile" /><!--imgFile和获取的参数名保持一致 -->
<input type="submit">
</form>
八、json格式的请求与返回处理:
依赖jar包:
jackson-annotations-x.x.x、jackson-core-x.x.x、jackson-databind-x.x.x
1.用@RequestBody将请求json字符串转换为对象:
请求json:
{"phone":"130000"}
实现代码:
@Controller
public class LoginControl {
@RequestMapping("login")
public String login(@RequestBody User user) { // @RequestBody将请求json字符串转换为对象
...
}
}
2.用@ResponseBody将返回对象转换为json字符串:
实现代码:
@Controller
public class LoginControl {
@RequestMapping("login")
@ResponseBody // @ResponseBody将返回对象转换为json字符串
public User login() {
User user = new User();
user.setName("无名");
return user;
}
}
返回json:
{"name":"无名"}
九、Restful风格实现:
说明:url以id值结尾,区分不同的请求,如http://.../login/1
1.用{id}+@PathVariable实现路径后跟id值访问:
@Controller
public class LoginControl {
@RequestMapping("login/{id}") //{id}不可更改,可在login后跟数值
public String login(@PathVariable String id) { // @PathVariable用于将{id}的值取出,赋值给id
// public String login(@PathVariable("id") String id2) { // 功能同上
...
}
}
2.配置拦截"/"后缀的请求路径(类似servlet配置),在<web-app>节点中加入:
<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
...
<servlet-mapping>
...
<!-- 配置拦截"/"后缀的请求路径 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
十、拦截器 (类似Servlet的Filter):
1.自定义拦截类,实现HandlerInterceptor接口,用于拦截所有没登录的路径请求,跳登录页面:
(1)使用场景:
没登录时访问:http://.../根目录/pay.action,被拦截后跳到login.jsp
发起登录请求:http://.../根目录/LoginGroup/login.action,不会被拦截。
(2)实现:
public class RequestInterceptor implements HandlerInterceptor {
// 1.preHandle方法在路径方法之前执行,return true为放行,return false为拦截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (request.getSession().getAttribute("token") == null) {//判断是否已经登录过,没登录跳登录输入页
response.sendRedirect("/TestWeb/login.jsp");
}
return true;
}
// 2.postHandle方法在路径方法return之前执行,拦截时不执行此方法。
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
// 3.此方法在路径方法之后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
2. 配置拦截器,在 spring-mvc.xml的<beans>节点中加入,不拦截正常登录路径请求:
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置拦截的路径,"/**"为拦截所有请求,包含所有子目录 -->
<mvc:mapping path="/**" />
<!--配置不拦截的路径,此处配置不拦截登录路径组的所有请求 -->
<mvc:exclude-mapping path="/LoginGroup/**" />
<!--配置自定义拦截类 -->
<bean class="com.yyh.hkw.control.RequestInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
3.登录请求处理类(处理正常登录请求,可以没有这一步):
@Controller
@RequestMapping("LoginGroup") //当前为登录路径组请求,已经配置为不会被拦截器拦截
public class LoginControl {
@RequestMapping("login")
public String login(String phone, String code, HttpSession session) {
System.out.println("login");
if("130".equals(phone) && "1".equals(code)) { //判断手机与验证码是否正确,正确通过,不正确跳登录界面
session.setAttribute("token", "dsaf654sd6455464d4f5"); //设置token到session中
return "/WEB-INF/jsp/login_success.jsp"; //跳登录成功界面
}
return "/login.jsp"; //跳登录输入界面
}
}
十一、其他:
1.配置静态资源不拦截,在spring-config.xml的<beans>节点中加入:
<beans>
...
<!-- 配置静态资源不拦截 -->
<mvc:default-servlet-handler />
</beans>