SpringMVC
1、回顾MVC
MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范
MVC不是一种设计模式,MVC是一种架构模式。不同的MVC存在差异。
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
Controller(控制器):接收用户请求,委托给模型进行处理,处理完毕后把返回的模型数据返回给视图,由视图负责展示。
model1&model2时代
Model1适用于快速开发小规模项目。
分为两层,视图层和模型层。
JSP页面身兼View和Controller两种角色.增加了应用的扩展性和维护的难度
Model2把一个项目分成三部分,包括视图、控制、模型
提高了代码的复用率与项目的扩展性,且大大降低了项目的维护成本。
2.关于SpringMVC
Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。
①拦截请求,查找控制器和处理器
DispatcherServlet
接收请求并拦截请求
HandlerMapping
根据请求url查找Handler
HandlerExecution
根据url查找控制器
②执行请求并返回
HandlerAdapter
表示处理器适配器,其按照特定的规则去执行Handler。Handler让具体的Controller执行。
Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView
。
③视图解析
ViewResolver
来解析HandlerAdapter传递的逻辑视图名。
最终视图呈现给用户。
实际操作:
①Controller层调用业务层
②设置视图返回的名字
使用springMVC
通过
与注解方式的区别,在②中加入
<!--处理器映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
...
在③中
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();
//业务代码
String result="Hello 猪猪";
mv.addObject("msg",result);
//视图跳转
mv.setViewName("test");
return mv;
}
}
然后将类交给Spring容器
<!--Handler-->
<bean id="/hello" class="com.kuang.controller.HelloController"/>
通过注解
①编写web.xml
<!--1.注册servlet-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--通过初始化参数指定SpringMVC配置文件的位置,进行关联-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 启动顺序,数字越小,启动越早 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--所有请求都会被springmvc拦截 -->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
②编写springmvc配置文件
<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="com.kuang.controller"/>
<!-- 让Spring MVC不处理静态资源 -->
<mvc:default-servlet-handler />
<!--在spring中一般采用@RequestMapping注解来完成映射关系。
而annotation-driven配置帮助我们自动完成上述两个实例的注入。-->
<!--支持mvc注解驱动-->
<mvc:annotation-driven />
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
③创建对应的controller
类 ,完善与前端的对应关系
@Controller
@RequestMapping("/HelloController")
public class HelloController {
//真实访问地址 : 项目名/HelloController/hello
@RequestMapping("/hello")
public String sayHello(Model model){
//向模型中添加属性msg与值,可以在JSP页面中取出并渲染
model.addAttribute("msg","hello,SpringMVC");
//web-inf/jsp/hello.jsp
return "hello";
}
}
④运行调试
总结
使用springMVC必须配置的三大件:
处理器映射器、处理器适配器、视图解析器
通常,我们只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可,而省去了大段的xml配置
3.RestFul 风格
简洁:风格简单
高效:支持缓存
安全:可以隐藏程序中的参数
①使用路径变量
使用 @PathVariable
注解,让方法参数的值对应绑定到一个URI模板变量上。
@RequestMapping("/commit/{p1}/{p2}")
public String index(@PathVariable int p1, @PathVariable int p2, Model model){}
②使用method属性指定请求类型
如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE等
浏览器地址栏进行访问默认是Get请求
//映射访问路径,必须是POST请求
@RequestMapping(value = "/hello",method = {RequestMethod.POST})
几个变体:@GetMapping
、@PostMapping
、@PutMapping
、@DeleteMapping
、@PatchMapping
4.转发和重定向
通过SpringMVC来实现转发和重定向 - 无需视图解析器;
①转发
return "/index.jsp";
return "forward:/index.jsp";
②重定向
return "redirect:/index.jsp";
有视图解析器可以简化转发的过程,无需写路径全命名
5.数据处理
①提交的域名称和处理方法的参数名一致
②提交的域名称和处理方法的参数名不一致,使用@RequestParam
public String hello(@RequestParam("username") String name){}
③提交的是一个对象
处理方法的参数使用对象即可
@RequestMapping("/user")
public String user(User user){}
使用对象的话,前端传递的参数名和对象名必须一致,否则就是null。
封装数据
Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解;
ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性;
ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。
乱码问题
SpringMVC提供了过滤器
<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>
极端情况下的解决方法:
①修改tomcat配置文件 : 设置编码!
②自定义过滤器
6.JSON
JSON是一种轻量级的数据交换格式,目前使用特别广泛。
JSON 是 JavaScript 对象的字符串表示法
//将js对象转换为json对象
var json = JSON.stringify(user);
//将json对象转换为js对象
var js = JSON.parse(json);
乱码问题
在springmvc-servlet.xml中加入
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
前后端分离开发
①方法返回json字符串
@Controller
@ResponseBody
②类返回json字符串
@RestController
内部操作:
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
...
//将我们的对象解析成为json格式
String str = mapper.writeValueAsString(user);
FastJson
阿里开发的一款包。专门用于方便的实现json对象与JavaBean对象的转换
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
7.Ajax
传统的网页(即不用ajax技术的网页),想要更新内容或者提交一个表单,都需要重新加载整个网页。
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
把主动权交给前端
AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
eg:在搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。
①导入jquery
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
②编写AjaxController类的方法
@RequestMapping("/a1")
public void ajax1(String name , HttpServletResponse response) throws IOException {
if ("admin".equals(name)){
response.getWriter().print("true");
}else{
response.getWriter().print("false");
}
}
③编写index.jsp在script中引入
$.post({
url:请求后端的地址
data:需要后端发送的数据,后端从这里取数据
success:成功之后执行的回调函数(全局)
error:失败之后执行的回调函数(全局)
})
实例:
<script>
function a(){
$.post({
url:"${pageContext.request.contextPath}/a1",
data:{'name':$("#txtName").val()},
success:function (data,status) {
alert(data);
alert(status); //200成功 300重定向转发 400客户端错误 500服务器错误
}
});
}
</script>
在body中
<%--失去焦点时,发送一个请求到后台--%>
用户名:<input type="text" id="txtName" onblur="a1()"/>
获取集合对象展示到前端
controller部分
@RequestMapping("/a2")
public List<User> ajax2(){
List<User> list = new ArrayList<User>();
list.add(new User("秦疆1号",3,"男"));
list.add(new User("秦疆2号",3,"男"));
list.add(new User("秦疆3号",3,"男"));
return list; //由于@RestController注解,将list转成json格式返回
}
script部分
<script>
$(function (){
$("#btn").click(function () {
// $.post(url,param[可以省略],success)
$.post("${pageContext.request.contextPath}/a2",function (data) {
// console.log(data);
var html="";
for (let i = 0; i < data.length; i++) {
html+="<tr>"+
"<td>"+data[i].name+"</td>"+
"<td>"+data[i].age+"</td>"+
"<td>"+data[i].sex+"</td>"+"</tr>";
}
$("#context").html(html);
});
})
})
</script>
body部分
<body>
<input type="button" value="加载数据" id="btn"/>
<table>
<tr>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
</tr>
<tbody id="context">
<!--数据:后台-->
</tbody>
</table>
</body>
验证用户名、密码
①控制器类
//由于@RestController注解,将msg转成json格式返回
@RequestMapping("/a3")
public String ajax3(String name,String pwd){
String msg = "";
//模拟数据库中存在数据
if (name!=null){
if ("admin".equals(name)){
msg = "OK";
}else {
msg = "用户名输入错误";
}
}
if (pwd!=null){
if ("123456".equals(pwd)){
msg = "OK";
}else {
msg = "密码输入有误";
}
}
return msg;
}
②前端页面 login.jsp
script部分
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.js"> </script>
function a1() {
$.post({
url:"${pageContext.request.contextPath}/a3",
data:{"name":$("#name").val()},
success:function (data) {
if(data==="ok"){
$("#userInfo").css("color","green");
}else {
$("#userInfo").css("color","red");
}
$("#userInfo").html(data);
console.log(data);
}
});
}
body部分
<p>
用户名:<input type="text" id="name" onblur="a1()"/>
<span id="userInfo"></span>
</p>
8.拦截器
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理
过滤器与拦截器的区别:拦截器是AOP思想的具体应用。
过滤器
servlet规范中的一部分,任何java web工程都可以使用
在url-pattern中配置了/*
之后,可以对所有要访问的资源进行拦截
拦截器
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的
①在springmvc的配置文件中配置拦截器
<!--关于拦截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--/** 包括路径及其子路径-->
<!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截-->
<!--/admin/** 拦截的是/admin/下的所有-->
<mvc:mapping path="/**"/>
<!--bean配置的就是拦截器-->
<bean class="com.kuang.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
②编写一个拦截器
public class MyInterceptor implements HandlerInterceptor {
//在请求处理的方法之前执行
//如果返回true执行下一个拦截器
//如果返回false就不执行下一个拦截器
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("------------处理前------------");
return true;
}
//在请求处理的方法执行之后
//在dispatcherServlet处理后执行,做清理工作.
验证用户是否登录
①编写拦截器
public class LoginInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
// 如果是登陆页面则放行
System.out.println("uri: " + request.getRequestURI());
if (request.getRequestURI().contains("login")) {
return true;
}
HttpSession session = request.getSession();
// 如果用户已登陆也放行
if(session.getAttribute("user") != null) {
return true;
}
// 用户没有登陆跳转到登陆页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
②在springmvc的配置文件中配置拦截器
9.上传与下载
前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;
上传
①
②采用file.Transto 来保存上传的文件