Spring MVC的优点
清晰地角色划分,灵活的配置功能,提供了大量的控制器接口和实现类,Spring提供了Web应用开发的一整套流程,不仅仅是MVC,他们之间可以很方便的结合一起。
Getting Started
1、目录
1.1、关于目录和文件
handler:处理器,用来处理请求和返回视图,可以认为等同于Servlet。
spring-mvc.xml:spring-mvc的核心配置
view:WEB-INF/view/的目录下用来放jsp
2、写一个handler类
Controller
将本handler类纳入容器
RequestMapping
设定类和方法的访问路径
@Controller //纳入容器
@RequestMapping("/user") //此handler的访问路径
public class UserHandler {
@RequestMapping("/login")//此方法的访问路径
public String login() {
System.out.println("login被调用了");
//返回名为“hello”的视图文件
return "hello";
}
}
解读: 在这里,当用户访问http://localhost:8080/项目名/user/login
时,会调用UserHandler
类的login
方法,然后返回WEB-INF/view/文件夹下的hello.jsp
文件。
为什么会这样呢?我们可以在下面xml中找到答案。
3、配置spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启基本注解 :识别 Controller,Service,Repository,Component,Autowired,Resource,Qulifer -->
<context:component-scan base-package="com.mvc"></context:component-scan>
<!-- 开启处理器映射器注解:识别 @RequestMapping,对该注解标注的类和方法做映射。-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<!-- 开启处理器适配器注解: 当有请求过来,dispatcherServlet找到该请求所映射到的处理器方法,该bean对象负责执行方法。封装参数 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<!-- 开启视图解析器:当处理器方法执行完成后,配置一个视图路径地址 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 视图文件前缀名(路径) -->
<property name="prefix" value="/WEB-INF/view/"></property>
<!-- 视图文件后缀名 -->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
3.1、标签头是固定套路
3.2、开启了纳入容器、依赖注入这些基本的注解,同时指定了"com.mvc"
包,这些包下的文件可省略路径名。
<context:component-scan base-package="com.mvc"></context:component-scan>
3.3、这三条spring mvc固定的套路,了解这些类的作用,平时复制即可,太长记不住。
prefix
前缀名 视图文件(此处为jsp文件)的从web文件根目录开始的路径。
suffix
后缀名 视图文件的的后缀名,此demo中为jsp
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
4、在web.xml中配置前端核心DispatcherServlet
spring-mvc.xml
是配置好了,但仍没有加载。在这里我们通过把spring-mvc.xml
的路径赋值给dispatcherServlet的contextConfigLocation属性来执行加载。
<servlet>
<!--核心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>
<load-on-startup>1</load-on-startup><!--设置启动顺序-->
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern> <!--url使用通配符-->
</servlet-mapping>
5、访问handler下的方法
启动tomcat
访问http://localhost:8080/项目名/user/login
网页显示了hello.jsp的内容
这些文字我预先写在了hello.jsp中
控制台输出
Getting Started里我们完成了一个demo,达成了通过url访问handler中方法的目的。
在理解这个demo的基础上,我们再来实现更多的功能。
Spring MVC功能详解
为了更好的演示接下来的功能,我们在demo中加入一个实体,一个service。
User 实体类
public class User {
//用户id 用户名 性别true、false
private Integer uid;
private String uname;
private boolean gender;
//还有get set方法
}
service接口及其实现类
public interface IUserService {
void login(Integer uid,String uname,boolean gender);
void update(User user);
}
@Service //纳入容器
public class UserServiceImpl implements IUserService {
@Override
public void login(Integer uid, String uname, boolean gender) {
System.out.println("service的login输出:"+uid+" "+uname+" "+gender);
}
@Override
public void update(User user) {
System.out.println("serviced的update输出:"+user);
}
}
添加service到之前的handler类
@Controller //纳入容器
@RequestMapping("/user") //访问路径
public class UserHandler {
@Autowired //依赖注入 ( UserHandler持有一个IUserService )
private IUserService ser;
@RequestMapping("login")
public String login(Integer uid,String uname,boolean gender) {
System.out.println("handler的login被调用了");
ser.login(uid, uname, gender);
return "hello";
}
@RequestMapping("update")
public String update(User user) {
System.out.println("handler的update被调用了");
ser.update(user);
return "hello";
}
}
1、获取页面提交的的表单元素
接收页面表单元素,要什么参数加对应的形参,要求形参名与表单元素名相同,类型会自动转型。
形参也可以是对象,会根据实体对象的属性自动获取参数。
演示
这里就不做表单了,直接使用url拼接。
如图,我们使用get方式,向handler提交了uid=123&uname=Tom&gender=false
控制台输出
那么使用User对象作为形参的update()
方法呢?
使用get方式提交
会根据实体对象的属性自动获取参数。
控制台输出
这里漏了写toString,没有展示user的属性值,懒得补了。
2、回传数据到页面
回传数据我们可以使用到Model
对象(org.springframework.ui.Model
)
添加了Model形参,使用addAttribute方法加入数据。其余和上面的代码一样。
UserHandler.java
@Controller //纳入容器
@RequestMapping("/user") //访问路径
public class UserHandler {
@Autowired //依赖注入
private IUserService ser;
@RequestMapping("login")
public String login(Integer uid,String uname,boolean gender,Model model) {
//为model添加回传数据
model.addAttribute("msg", "登录成功!");
//其余和之前一样
System.out.println("login被调用了");
ser.login(uid, uname, gender);
return "hello";
}
hello.jsp
在jsp中使用EL调用回调数据
<body>
user处理器的方法执行后,跳转到了hello.jsp页面
${msg}
</body>
运行
打印了回传函数msg的值 “登录成功”
控制台输出和之前一样,这里就不写了。
除了使用Model对象回传参数,还可以使用ModelAndView
使用ModelAndView,方法的返回值需要是ModelAndView,要在方法体内设置视图文件。
@Controller //纳入容器
@RequestMapping("/user") //访问路径
public class UserHandler {
@RequestMapping("/update")
//返回值类型设置为ModelAndView
public ModelAndView update() {
//新建ModelAndView对象
ModelAndView model=new ModelAndView();
//设置回传参数
model.addObject("msg", "更新成功");
//设置视图文件
model.setViewName("hello");
return model;
}
}
运行
跳转到了指定的,hello.jsp
页面,显示了回传函数msg的值。
设置视图文件的2种方法
// 1、创建时指定视
ModelAndView model=new ModelAndView("hello");
// 2、创建后指定
ModelAndView model=new ModelAndView();
model.setViewName("hello");
3、获取servlet核心对象
对于HttpServletRequest、HttpServletResponse,HttpSession,ServletContext对象,在处理器方法内部,需要用哪个对象,加哪个形参就好了。
这里拿HttpServletResponse举例
@Controller //纳入容器
@RequestMapping("/user") //访问路径
public class UserHandler {
@RequestMapping("select")
public void select(int uid,HttpServletResponse resp) { //加了serponse的形参
//设置编码格式
resp.setContentType("text/html;charset=utf-8");
try {
PrintWriter pw=resp.getWriter();
pw.println("查询了"+uid+"号用户的资料!");
pw.flush();
pw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行
其他的servlet核心对象和这差不多,就不一一演示了。
4、handler之间的重定向
在handler中,return的值加上forward就可以重定向到其他handler。
@RequestMapping("test1")
public String test1() {
System.out.println("test1运行了");
return "forward:select";
}
@RequestMapping("test2")
public String test2() {
System.out.println("test2运行了");
return "hello";
}
运行
控制台输出
转发使用 redirect:
转发到web文件夹根目录的index.html
@RequestMapping("test1")
public String test1() {
System.out.println("test1运行了");
return "redirect:/index.html";
}
=
5、乱码问题
在web.xml中配置过滤器,将编码格式设置为utf-8
web.xml
<filter>
<filter-name>characterEncoding</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>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
6、设置请求方法get | post
@RequestMapping(params="处理器访问名",method=RequestMethod.POST|GET)
在处理器方法中如何设置客户端请求的方式,要么get要么post,或者都可以。
@RequestMapping(params="login",method=RequestMethod.POST)
public void login(String uname,String pwd) {
service.login(uname,pwd);
}
7、默认值
如果形参是int,double,boolean,long等这些非String类型的,有可能出现转型异常,可以设置默认值。
@RequestParam(defaultValue="10")
value:
参数名字,即入参的请求参数名字,若相同可不写。
required:
是否必须,如果为true而页面没有提交将报404错误码,默认是true。
defaultValue:
默认值
public void login(@RequestParam(defaultValue="admin",required =false)String uname,@RequestParam(defaultValue="123456",required =false)String pwd) {
ser.login(uname, pwd);
}