SpringMVC1~~~
快速入门
spring容器文件
在src下就是applicationContext-mvc.xml,需要在web.xml指定<init-param>,给DispatcherServlet指定要去操作的spring容器文件
在WEB-INF下就是xxx-servlet.xml,不需要在web.xml指定<init-param>,如果我们没有配置 contextConfigLocation,默认按照这样的位置去定位spring配置文件
/WEB-INF/springDispatcherServlet-servlet.xml
<!--配置自动扫描包-->
<context:component-scan base-package="com.web"/>
<!--配置视图解析器[默认视图解析器]-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置属性suffix 和 prefix-->
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
<!--调整优先级-->
<property name="order" value="10"/>
</bean>
web.xml
<!--配置前端控制器/中央控制器/分发控制器
用户的请求都会经过它的处理
-->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置属性 contextConfigLocation, 指定DispatcherServlet 去操作的spring配置文件-->
<!--<init-param>-->
<!-- <param-name>contextConfigLocation</param-name>-->
<!-- <param-value>classpath:applicationContext-mvc.xml</param-value>-->
<!--</init-param>-->
<!--在web项目启动时,就自动的加载DispatcherServlet-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<!--
配置的url-pattern是 / ,表示用户的请求都经过 DispatcherServlet
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
UserServlet
@Controller
public class UserServlet {
//编写方法,响应用户的请求
/**
* 1. login() 方法是用于响应用户的登录请求
* 2. @RequestMapping(value = "/login") 类似我们以前在原生的Servlet
* 配置 url-pattern, 就是给方法配置一个url映射
* 3. 即当用户在浏览器输入 http://localhost:8080/web工程路径/login 就能够访问到login()
* 4. return "login_ok"; 表示返回结果给视图解析器(InternalResourceViewResolver)
* , 视图解析器会根据配置,来决定跳转到哪个页面
*
* <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
*
* <property name="prefix" value="/WEB-INF/pages/"/>
* <property name="suffix" value=".jsp"/>
* </bean>
*
* 根据上面的配置 return "login_ok"; 就是转发到 /WEB-INF/pages/login_ok.jsp
*/
@RequestMapping(value = "/login")
public String login() {
System.out.println("login ok.......");
return "login_ok";
}
}
细节
执行流程
@RequestMapping
可以指定控制器/处理器的某个方法的请求的url
修饰方法、类和指定请求方式
当同时修饰类和方法时, 请求的url就是组合:/类请求值/方法请求值
buy()方法请求的url: http://ip:port/工程路径/user/buy
@RequestMapping(value = "/user")
@Controller //UserHandler就是一个处理器/控制器,注入到容器
public class UserHandler {
@PostMapping(value = "/buy")
public String buy() {
System.out.println("购买商品~");
return "success";
}
}
RequestMethod 四个常用选项 POST, GET, PUT, DELETE
SpringMVC 控制器默认支持GET和POST两种方式,如果指定,必须按照指定方式请求
@PostMapping(value = "/buy")等价@RequestMapping(value = "/buy",method = RequestMethod.POST)
<form action="user/buy" method="post">
购买人:<input type="text" name="username"><br>
够买量:<input type="text" name="nums"><br>
<input type="submit" value="购买">
</form>
指定params和headers支持简单表达式
@RequestMapping(value = "/find", params = "bookId=100", method = RequestMethod.GET)
public String search(String bookId) {
System.out.println("查询书籍 bookId= " + bookId);
return "success";
}
params="bookId" 表示请求该目标方法时,必须给一个bookId参数, 值没有限定
search(String bookId): 表示请求目标方法时, 携带的bookId=100, 就会将请求携带的bookId对应的值 100, 赋给 String bookId
params = "bookId=100" 表示必须给一个bookId参数, 而且值必须是100
<hr><h1>演示params的使用</h1>
<a href="user/find?bookId=100">查询书籍</a>
支持Ant风格资源地址
//要求: 可以配置 /user/message/aa, /user/message/aa/bb/cc
@RequestMapping(value = "/message/**")
public String im() {
System.out.println("发送消息");
return "success";
}
<hr><h1>演示Ant风格的请求资源方式 </h1>
<a href="user/message/aa">发送消息1</a><br>
<a href="user/message/aa/bb/cc">发送消息2</a><br>
配合@PathVariable映射URL绑定的占位符
不需要在url地址上带参数名,更加简洁明了
//要求: 获取到 username 和 userid
//前端页面: <a href="user/reg/kristina/300">占位符的演示</a>
//(value = "/reg/{username}/{userid}"):,表示kristina->{username} 300=>{userid}
// value{}大括号的名字随便写,PathVariable里的名字必须跟value{}里保持一致
@RequestMapping(value = "/reg/{username}/{userid}")
public String register(@PathVariable("username") String name,
@PathVariable("userid") String id) {
System.out.println("接收到参数--" + "username= " + name + "--" + "usreid= " + id);
return "success";
}
<hr><h1>占位符的演示</h1>
<a href="user/reg/kristina/300">占位符的演示</a>
细节
映射的URL不能重复
@RequestMapping(value = "/hi")
public String hi() {}
@RequestMapping(value = "/hi")
public String hi() {}
请求简写
@GetMapping、@PostMapping、@PutMapping、@DeleteMapping
//@RequestMapping(value = "/buy",method = RequestMethod.POST)
@PostMapping(value = "/buy")
public String buy() {
System.out.println("购买商品~");
return "success";
}
如果确定表单或者超链接会提交某个字段数据(比如email),要求提交的参数名和目标方法的参数名保持一致
@GetMapping(value = "/hello3")
public String hello3(String email) {
System.out.println("hello3 " + email);
return "success";
}
localhost:8080/user/hello3?email=tom@sohu.com
如果请求参数有 email=xx, 就会将传递的值,赋给String emai,否则输出null
Rest
web.xml
<!--配置HiddenHttpMethodFilter
1. 作用是 把 以pos t方式提交的delete和put请求进行转换
2. 配置url-pattern 是 /* 表示请求都经过 hiddenHttpMethodFilter过滤
-->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
spring容器文件
<!--加入两个常规配置-->
<!--支持SpringMVC的高级功能,比如JSR303校验, 映射动态请求-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--将springmvc不能处理的请求,交给tomcat处理,比如css, js-->
<mvc:default-servlet-handler/>
HiddenHttpMethodFilter源码
将POST请求转换成PUT、DELETE、PATCH
按照_method参数名来读取
public static final String DEFAULT_METHOD_PARAM = "_method";
---------------------------------------------------
private static final List<String> ALLOWED_METHODS =
Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(),
HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
---------------------------------------------------
if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
if (ALLOWED_METHODS.contains(method)) {
requestToUse = new HttpMethodRequestWrapper(request, method);
}
}
}
Delete、Put
默认情况下 <a href="user/book/600">删除指定id的书</a> 是get
需要将 get <a href="user/book/600">删除指定id的书</a> 以post方式提交给后端handler, 这样过滤器才会生效
//删除[DELETE]
@RequestMapping(value = "/book/{id}", method = RequestMethod.DELETE)
public String delBook(@PathVariable("id") String id) {
System.out.println("删除书籍 id= " + id);
//return "success"; //[如果这样返回会报错 JSPs only permit GET POST or HEAD]
//1. redirect:/user/success重定向
//2. 会被解析成 /springmvc/user/success
return "redirect:/user/success";
}
//如果请求是 /user/success , 就转发到 success.jsp
//successGenecal对应的url http://ip:port/springmvc/user/success
@RequestMapping(value = "/success")
public String successGenecal() {
return "success"; //由该方法 转发到success.jsp页面
}
//修改[PUT]
@PutMapping(value = "/book/{id}")
public String updateBook(@PathVariable("id") String id) {
System.out.println("修改书籍 id=" + id);
return "redirect:/user/success";
}
<html>
<head>
<title>rest </title>
<%-- 引入jquery--%>
<script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
$(function () {
//给删除超链接绑定一个点击事件
$("#deleteBook").click(function (){
$("#hiddenForm").attr("action", this.href);
$(":hidden").val("DELETE");
$("#hiddenForm").submit();
return false; //改变点击超链接的行为, 不再提交
})
})
</script>
</head>
<body>
<h3>rest风格的url, 删除一本书</h3>
<a href="user/book/600" id="deleteBook">删除指定id的书</a>
<form action="" method="post" id="hiddenForm">
<input type="hidden" name="_method"/>
</form>
<br><hr>
<h3>rest风格的url 修改书籍[put]~</h3>
<form action="user/book/666" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="修改书籍~">
</form>
</body>
</html>
细节
SpringMVC映射请求数据
RequestParam获取参数值
@RequestParam(value="name", required=false)
1. 获取到超链接传递的数据 请求 http://localhost:8080/springmvc/vote/vote01?name=xx
2. @RequestParam 表示会接收提交的参数
3. value="name" 表示提交的参数名是name
4. required=false 表示该参数可以没有, 默认是true,表示必须有这个参数
5. 当我们使用了@RequestParam(value="name", required=false)后就请求的参数名和方法的形参名可以不一致
@RequestMapping(value = "/vote01")
public String test01(@RequestParam(value = "name", required = false) String username) {
System.out.println("得到的username= " + username);
//返回到一个结果
return "success";
}
<h2>获取到超链接参数值</h2>
<a href="vote/vote01?name=hsp">获取超链接的参数</a>
获取http请求消息头
/**
* 需求: 获取http请求头信息, 获取到Accept-Encoding 和 Host
* @RequestHeader("Http请求头字段")
*/
@RequestMapping(value = "/vote02")
public String test02(@RequestHeader("Accept-Encoding") String ae,
@RequestHeader("Host") String host) {
System.out.println("Accept-Encoding= " + ae);
System.out.println("Host= " + host);
//返回到一个结果
return "success";
}
<h1>获取到消息头</h1>
<a href="vote/vote02">获取http消息头信息</a>
获取javabean形式的数据
1. 方法的形参用对应的类型来指定即可, SpringMVC会自动的进行封装
2. 如果自动的完成封装, 要求提交的数据,参数名和对象的字段名保持一致
3. 如果属性是对象,这里就是仍然是通过 字段名.字段名
比如Master [pet], 即提交的数据 参数名是 pet.id pet.name, 这就是级联操作
4.表单控件的name与javabean属性名对应
@RequestMapping(value = "/vote03")
public String test03(Master master) {
System.out.println("master=" + master);
return "success";
}
<form action="vote/vote03" method="post">
主人号:<input type="text" name="id"><br>
主人名:<input type="text" name="name"><br>
宠物号:<input type="text" name="pet.id"><br>
宠物名:<input type="text" name="pet.name"><br>
<input type="submit" value="添加主人和宠物">
</form>
获取servlet api
引入tomcat/lib下的servlet-api.jar
@RequestMapping(value = "/vote04")
public String test04(HttpServletRequest request,
HttpServletResponse response,
HttpSession hs) {
//获取到session
//servlet原生的方式
HttpSession session = request.getSession();
System.out.println("session=" + session);
//注意:通过参数传入的 hs 和 通request.getSession() 得到的对象是
//同一个
System.out.println("hs= " + hs);
String username = request.getParameter("username");
String pwd = request.getParameter("pwd");
System.out.println("username= " + username);
System.out.println("pwd= " + pwd);
return "success";
}
<h1>演示 servlet api的使用 </h1>
<form action="vote/vote04" method="post">
用户名:<input type="text" name="username"><br>
密 码:<input type="password" name="pwd"><br>
<input type="submit" value="添加用户">
</form>
模型数据
数据放入request
默认机制
/**
* 将提交的数据->springmvc封装到java对象->springmvc 会自动的将其放入到request域
* 就可以在跳转到的页面取出数据.
*/
@RequestMapping(value = "/vote05")
public String test05(Master master) {
return "vote_ok";
}
<h1>添加主人信息</h1>
<form action="vote/vote05" method="post">
主人号:<input type="text" name="id"><br>
主人名:<input type="text" name="name"><br>
宠物号:<input type="text" name="pet.id"><br>
宠物名:<input type="text" name="pet.name"><br>
<input type="submit" value="添加主人和宠物">
</form>
<h1>获取的的数据显示页面</h1>
<hr>
取出 request域的数据-通过前面讲解的el表达式来获取即可
<br>
address: ${requestScope.address}<br>
主人名字= ${requestScope.master.name}
主人id= ${requestScope.master.id}
宠物名字= ${requestScope.master.pet.name}
<a href="<%=request.getContextPath()%>/homework/login.jsp">返回重新登录</a>
通过HttpServletRequest
springmvc默认存放对象到request域中,属性名是 类名/类型名 首字母小写
request域 ("master", master100)
所以在jsp中按照类名首字母小写来取出
@RequestMapping(value = "/vote05")
public String test05(Master master100, HttpServletRequest request) {
//设置某一字段的属性值
request.setAttribute("address", "beijing");
//修改name的属性值
master100.setName("nono");
return "vote_ok";
}
通过请求的方法参数Map<String,Object>
@RequestMapping(value = "/vote06")
public String test06(Master master, Map<String, Object> map) {
System.out.println("------test06-----");
//原理分析:springmvc会遍历map,然后将map的k-v, 存放到request域
map.put("address", "beijing...");
//map.put("master", null);
return "vote_ok";
}
通过返回ModelAndView对象
@RequestMapping(value = "/vote07")
public ModelAndView test07(Master master) {
System.out.println("----test07----");
ModelAndView modelAndView = new ModelAndView();
//放入属性到modelAndView对象
modelAndView.addObject("address", "shanghai");
//modelAndView.addObject("master", null);
//可以把从数据库得到的数据->对象-》放入modelAndView[Service-dao-db]
//这里指定跳转的视图名称
modelAndView.setViewName("vote_ok");
//返回结果
return modelAndView;
}
细节
数据放入session
@RequestMapping(value = "/vote08")
public String test08(Master master, HttpSession httpSession) {
System.out.println("----test08----");
//master对象是默认放在request域
//我们将master对象放入到session域
httpSession.setAttribute("master", master);
httpSession.setAttribute("address", "guangzhou");
return "vote_ok";//请求转发
}
<h1>添加主人信息[测试session]</h1>
<form action="vote/vote08" method="post">
主人号:<input type="text" name="id"><br>
主人名:<input type="text" name="name"><br>
宠物号:<input type="text" name="pet.id"><br>
宠物名:<input type="text" name="pet.name"><br>
<input type="submit" value="添加主人和宠物">
</form>
取出 session域的数据 <br>
address: ${sessionScope.address}<br>
主人名字= ${sessionScope.master.name}
主人信息= ${sessionScope.master}
@ModelAttribute实现prepare方法
/**
* 1. 当Handler的方法被标识 @ModelAttribute,就视为一个前置方法
* 2. 当调用该Handler的其它的方法时,都会先执行该前置方法
* 3. 类似我们前面讲解Spring时,AOP的前置通知[底层是AOP机制]
* 4. prepareModel前置方法,会切入到其它方法前执行..
*/
@ModelAttribute
public void prepareModel(){
System.out.println("prepareModel()-----完成准备工作-----");
}
视图和视图解析器
自定义视图
多个视图解析器,会根据优先级放在arraylist中进行遍历
默认视图解析器一旦执行,就不会执行自定义视图解析器
@RequestMapping(value = "/buy")
public String buy() {
System.out.println("------buy()-----");
return "hspView";
}
/**
* 1. MyView继承了AbstractView, 就可以作为一个视图使用
* 2. @Component(value = "myView"),该视图会注入到容器中, 名字/id是 hspView
*/
@Component(value = "hspView")
public class MyView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
//完成视图渲染
//并且可以确定我们要跳转的页面 [请求转发] /WEB-INF/pages/my_view.jsp
System.out.println("进入到自己的视图..");
//1. 下面就是进行请求转发到 /WEB-INF/pages/my_view.jsp
//2. /WEB-INF/pages/my_view.jsp 会被springmvc解析
// /springmvc/WEB-INF/pages/my_view.jsp
request.getRequestDispatcher("/WEB-INF/pages/my_view.jsp")
.forward(request, response);
}
}
<!--
1. 配置自定义视图解析器BeanNameViewResolver
2. BeanNameViewResolver可以去解析我们自定义的视图
3. 配置 属性 order, 表示视图解析器执行的顺序, 值越小, 优先级越高
4. 属性 order 的默认值是最低优先级 ,值为 Integer.MAX_VALUE
int LOWEST_PRECEDENCE = 2147483647
-->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="99"/>
</bean>
<a href="goods/buy">点击到自定义视图-</a><br/>
目标方法直接指定转发或重定向
访问WEB-INF下面的资源必须请求转发,不能直接浏览器访问
//直接指定要请求转发的或者是重定向的页面
@RequestMapping(value = "/order")
public String order() {
System.out.println("=======order()=====");
//请求转发到 /WEB-INF/pages/my_view.jsp
//下面的 /WEB-INF/pages/my_view.jsp 被解析成 /springmvc/WEB-INF/pages/my_view.jsp
//return "forward:/WEB-INF/pages/my_view.jsp";
//return "forward:/aaa/bbb/ok.jsp";
//直接指定要重定向的页面
//1. 对于重定向来说,不能重定向到 /WEB-INF/ 目录下
//2. redirect 关键字,表示进行重定向
//3. /login.jsp 在服务器解析 /springmvc/login.jsp
return "redirect:/login.jsp";
// /WEB-INF/pages/my_view.jsp 被解析 /springmvc/WEB-INF/pages/my_view.jsp
//return "redirect:/WEB-INF/pages/my_view.jsp";
}
forward对应InternalResourceView视图
redirect对应RedirectView视图