快速入门
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
<!--配置HiddenHttpMethodFilter1. 作用是 把 以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/successreturn "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}
通过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前置方法,会切入到其它方法前执行..*/@ModelAttributepublic void prepareModel(){System.out.println("prepareModel()-----完成准备工作-----");}
视图和视图解析器
自定义视图
自定义视图不存在会执行默认视图
@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 {@Overrideprotected void renderMergedOutputModel(Map<String, Object> model,HttpServletRequest request,HttpServletResponse response) throws Exception {//完成视图渲染//并且可以确定我们要跳转的页面 [请求转发] /WEB-INF/pages/my_view.jspSystem.out.println("进入到自己的视图..");//老师解读//1. 下面就是进行请求转发到 /WEB-INF/pages/my_view.jsp//2. /WEB-INF/pages/my_view.jsp 会被springmvc解析// /springmvc/WEB-INF/pages/my_view.jsprequest.getRequestDispatcher("/WEB-INF/pages/my_view.jsp").forward(request, response);}
}
<!--1. 配置自定义视图解析器BeanNameViewResolver2. BeanNameViewResolver可以去解析我们自定义的视图3. 配置 属性 order, 表示视图解析器执行的顺序, 值越小, 优先级越高4. 属性 order 的默认值是最低优先级 ,值为 Integer.MAX_VALUEint LOWEST_PRECEDENCE = 2147483647--><bean class="org.springframework.web.servlet.view.BeanNameViewResolver"><property name="order" value="99"/></bean>
<a href="goods/buy">点击到自定义视图-</a><br/>