一、MVC设计模式简介
MVC 是一种著名的设计模式,特别是在 Web 应用程序领域。模式全都是关于将包含业务数据的模块与显示模块的视图解耦的。
视图(例如,JSP 页面)怎样能够与其模型(例如,包含数据的 JavaBean)解耦?
在模型和视图之间引入重定向层可以解决问题。此重定向层是控制器。控制器将接收请求,执行更新模型的操作,然后通知视图关于模型更改的消息。依赖于模型的状态并且依赖于请求的控制器可以决定要显示哪个视图。
Spring MVC是Spring Framwork的一部分,是基于Java实现的轻量级Web框架。
Spring 的 Web MVC 模块是围绕 DispatcherServlet 而设计的。DispatcherServlet 给处理程序分派请求,执行视图解析。
springmvc的核心控制器,所有的请求到来后,首先经过的DispatcherServlet 。
二、使用XML配置SpringMVC的环境搭建
2.1 创建maven项目,引入依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.8</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<!-- spring 操作jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.8</version>
</dependency>
<!--AOP相关-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7.M3</version>
</dependency>
<!--jsp的依赖-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<!--jstl标签的依赖-->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
2.2 把maven项目添加了web模块
步骤:点击项目,右键,add framework support ,选择 webapplication打对勾
2.3 配置springmvc.xml核心配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
</beans>
2.4 编写web.xml文件,配置前端核心控制器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置SpringMVC的前端核心控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
关于DispatcherServlet的配置信息
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- <url-pattern>/</url-pattern>
里面的 / 代表的意思就是除了 jsp的页面请求放行之外,要拦截所有的请求 ,因为springmvc默认的模板引擎是jsp
-->
2.5 创建Controller,实现Controller接口
重写handleRequest
package cn.hxzy.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class UserController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("hello,springmvc");
return null;
}
}
2.6 编写springmvc.xml配置信息,添加视图解析器
通过BeanNameUrlHandlerMapping的方式完成请求与Controller之间的映射关系
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<bean name="/user" class="cn.hxzy.controller.UserController"/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp"/>
<!--/WEB-INF/jsp/index.jsp-->
</bean>
</beans>
2.7、ModelAndView的使用
Model模型数据,View是返回的视图名称
package cn.hxzy.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class IndexController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("hello,这是首页!");
ModelAndView mad=new ModelAndView();//模型和视图对象
mad.addObject("message","hello,这是首页!");
mad.setViewName("index"); //逻辑视图名
return mad;
}
}
2.8 lib目录添加jar包
配置Artifacts实例,添加lib目录,把maven项目的jar包添加到lib目录下。
2.9 配置tomcat
进行测试
三、使用注解形式配置SpringMVC的开发环境
3.1、在核心配置文件中添加注解
<context:component-scan base-package="cn.hxzy.controller"/>
<mvc:annotation-driven/>
3.2、在Controller类上添加@Controller注解
3.3、在方法上添加@RequestMapping注解
3.4、@ResponseBody注解
3.5、参数入参
//一般会在handle方法的参数上标注@RequestParam参数,也可以直接指定名字,如果指定了名字的话,入参的参数必须为指定的名字。
@RequestMapping("index")
public String getIndex(@RequestParam("uname") String userName, @RequestParam("age") Integer age) {
}
//@RequestParam("uname")是可以缺省的。
//有些时候某些接口的参数不需要全部都指定的时候,就可以使用@RequestParam来进行设置
@RequestParam("uname") String userName, @RequestParam(value = "age",required = false)
3.6、@RequestMapping的使用
@GetMapping //只能接收get请求
@PostMapping //只能接收post请求
@RequestMapping //标注在controller
3.7、跨域的注解
@CrossOrigin //跨域的注解
@CrossOrigin(value = {"http://127.0.0.1:8848"},allowCredentials="true")
3.8、@RequestBody注解
注意:前提必须:使用@PostMapping注解接收
直接拿对象进行映射:传统的web表单提交,如果要使用异步(axios)提交,必须加一个注解。
HTTP状态 415 , 不支持的媒体类型
HTTP状态400,最大几率是出现了数据类型不一致的问题,简单来说是Controller层不用正确读取你发送请求附带的参数
HTTP状态406,返回的数据,解析不了默认的数据格式类型,也得借助jackson工具来进行转换为json格式。请求头(Request Headers)中看到Accept优先是application/json格式,而响应头(Response Hraders)中却发现返回信息的格式是“text/html”,前台无法解析,需将结果转换成json格式返回给前台。
从请求的body区域获取数据
如果使用传统的表单方式去提交,对象可以直接入参,无需添加@RequestBody注解
@ResponseBody
@RequestMapping(value = "login")
public String login(@RequestBody User user) {
System.out.println(user);
return "123";
}
@RequestBody注解在参数中只能出现一次
遇到415异常后,使用Jackson工具来解决。
四、JSON的使用
4.1、JackSon工具的使用
4.1.1 导入依赖
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.13.0</version>
</dependency>
说明:
Jackson-datatype-jsr310是指Jackson的扩展库,用于支持Java 8新的日期和时间API(JSR-310)与Java对象之间的序列化和反序列化。JSR-310是Java 8发布的一项新的标准,它提供了一组强类型的日期和时间API,解决了Java标准库中日期处理的不足和问题。
添加完依赖后,然后在项目的lib中添加。
4.1.2 项目中应用
后台:
package cn.hxzy.controller;
import cn.hxzy.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
@author:mengshujun
@createTime: 2024-04-08 16:45:39 星期一
*/
@Controller
@RequestMapping("/user")
@CrossOrigin
public class UserController {
@RequestMapping("/login")
@ResponseBody
public String login(@RequestBody User user){
System.out.println(user.getUserNo());
System.out.println(user.getUserPwd());
return "success";
}
}
前端:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>用户登陆</title>
</head>
<body>
<div id="app">
<form>
<label>账号:</label><input type="text" placeholder="请输入手机号/邮箱" v-model="user.userNo" /><br />
<label>密码:</label><input type="password" placeholder="请输入密码" v-model="user.userPwd" /><br />
<input type="button" value="登录" @click="login()" />
</form>
</div>
</body>
<script src="./js/vue.min.js"></script>
<script src="./js/axios.min.js"></script>
<script type="text/javascript">
new Vue({
el: "#app",
data: {
user: {}
},
methods: {
login() {
axios.post("http://localhost:8080/hello/login",this.user) // Content-Type: application/json
.then(res=>{
alert(res.data)
})
}
}
})
</script>
</html>
@RestController是组合注解,是@Controller与@ResponseBody注解的组合。
List<String>
String []
List<User>
类型注入省略
4.2、解决中文乱码情况
4.2.1 自定义过滤器
package cn.hxzy.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CharacterEncodingFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest) servletRequest;
HttpServletResponse response=(HttpServletResponse)servletResponse;
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
filterChain.doFilter(request,response);
}
public void destroy() {
}
}
4.2.2 内置的过滤器,在web.xml中进行配置
<filter>
<filter-name>encodingFilter</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>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意,使用web.xml配置Filter时,必须放在配置文件的最前面
因为springmvc的默认消息转换器的优先级高与filter
4.3、 日期格式的映射
@DateTimeFormat注解
后台
package cn.hxzy.controller;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
/**
@author:mengshujun
@createTime: 2024-04-09 15:03:46 星期二
*/
@RestController
@CrossOrigin
public class DateController {
@RequestMapping("/dt")
public String dateformat(@RequestParam(required = false) Date date1, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date date2, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")Date date3){
System.out.println(date1);
System.out.println(date2);
System.out.println(date3);
return "ok";
}
}
前端
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>用户登陆</title>
</head>
<body>
<div id="app">
<form>
<input type="button" value="提交" @click="sub()" />
</form>
</div>
</body>
<script src="./js/vue.min.js"></script>
<script src="./js/axios.min.js"></script>
<script type="text/javascript">
new Vue({
el: "#app",
data: {
date1:"2024/4/9",
date2:"2024-4-8",
date3:"2024-4-8 13:20:31"
},
methods: {
sub() {
axios.get("http://localhost:8080/dt?date3="+this.date3)
.then(res=>{
alert(res.data)
})
}
}
})
</script>
</html>
4.4、格式化double类型的数据,保留两位小数
-
定义一个类,继承JsonSerializer类,重写里面的serialize方法,定义格式化规则
package cn.hxzy.config; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; import java.text.DecimalFormat; public class DoubleFormat extends JsonSerializer<Double> { private DecimalFormat df=new DecimalFormat("#.00"); public void serialize(Double aDouble, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { if(aDouble!=null){ jsonGenerator.writeString(df.format(aDouble)); } } }
2.在实体类的属性上添加注解,引入自己定义的规则
@JsonSerialize(using = DoubleFormat.class) private Double userMoney;
4.5、跨域的配置
跨域并不会阻止请求的发出,也不会阻止请求的接收,跨域是浏览器为了保护当前页面,你的请求得到了响应,浏览器不会把响应的数据交给页面上的回调,取而代之的是去提示你这是一个跨域数据。
开放单个IP
package com.hxzy.news.filter; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CrossFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)servletRequest; HttpServletResponse response = (HttpServletResponse)servletResponse; // 允许跨域的地址*表示所有 response.setHeader("Access-Control-Allow-Origin", "*"); // 表示是否允许发送Cookie response.setHeader("Access-Control-Allow-Credentials", "true"); // 允许跨域的方法 response.setHeader("Access-Control-Allow-Methods", "POST,GET,PUT,DELETE"); // 预检请求的有效期,OPTIONS请求就是想服务端进行探测支持的方法 response.setHeader("Access-Control-Max-Age", "3600"); // 跨域时允许的请求头字段 response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,Token"); // 检测时直接返回 if ("OPTIONS".equals(request.getMethod())) { response.setStatus(HttpServletResponse.SC_NO_CONTENT); return; } filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }
多个IP的配置
package cn.hxzy.myschool.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @WebFilter("/*") public class CorsFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; // IP地址列表 String[] arr = {"http://192.168.8.51:8848", "http://192.168.8.74:8848"}; Set<String> set=new HashSet<String>(Arrays.asList(arr)); String originHeader = request.getHeader("Origin"); if(set.contains(originHeader)){ response.setHeader("Access-Control-Allow-Origin",originHeader); // 表示是否允许发送Cookie response.setHeader("Access-Control-Allow-Credentials", "true"); // 允许跨域的方法 response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,DELETE,PUT"); // 预检请求的有效期,OPTIONS请求就是想服务端进行探测支持的方法 response.setHeader("Access-Control-Max-Age", "3600"); // 跨域时允许的请求头字段 response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,Token"); } // 检测时直接返回 if ("OPTIONS".equals(request.getMethod())) { response.setStatus(HttpServletResponse.SC_NO_CONTENT); return; } filterChain.doFilter(servletRequest, servletResponse); } public void destroy() { } }
注解实现
//@CrossOrigin(value = "http://192.168.8.74:8848") @CrossOrigin(value = {"http://192.168.8.51:8848"},allowCredentials = "true")
前端设置ajax
-
xhrFields: {withCredentials: true}, crossDomain:true,
五、使用Servlet API对象作为入参
package cn.hxzy.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @Controller public class IndexController { @RequestMapping("go") public String go() { return "user"; } @RequestMapping("toLogin") public String login(HttpServletResponse response, HttpServletRequest request, Model model) { HttpSession session = request.getSession(); session.setAttribute("userName", "zhangsan"); model.addAttribute("session", session); return "user"; } }
说明:如果需要用到Servlet 对象,则只需要在方法的参数中进行设置即可使用。
六、Rest ful风格API
Representational State Transfer,表述性状态转移,是一种软件架构风格
Spring MVC提供对REST风格的支持
优点:简洁,高效,安全
基于REST构建的API就是
Restful
风格。请求示例:
/student/selectStudent?id=1 /student/select/1 //get 模糊:/student/list/name /student/save //post /student/delete/1 //delete /student/update/13 //put /student/update/13/cardNo //修改put //patch
请求方式的配置
@RequestMapping(value = "index",method= RequestMethod.POST) /*RequestMethod是一个枚举类型的值,其中包含 GET, //用于获取资源 HEAD, //获取资源的头信息 POST, //用于提交数据 PUT, //用于更新数据 PATCH, //用于局部更新数据 DELETE, //用于删除数据 OPTIONS, //用于获取服务器支持的请求方法 TRACE; //用于回显服务器收到的请求 <a href="/user">跳转到</a> 超链接是get请求。
6.1、@PathVariable与@RequestParam 区别
相同点:都是用于从request中接收请求的,两个都可以接收参数
不同点:@RequestParam 是从request里面取值,而 @PathVariable 是从一个URI模板里面来填充
@PathVariable的比@RequestParam 安全,不会暴露敏感参数名称。
统一接口。Restful风格的数据元操作CRUD(create,read,update,delete)分别对应HTTP方法:
GET用来获取资源,POST用来新建资源(也可以用于更新资源),
PUT用来更新资源,DELETE用来删除资源,这样就统一了数据操作的接口
如果是查询请求,Controller使用@GetMapping,如果是新增操作,Controller使用@PostMapping,如果是更新操作,Controller使用@PutMapping
,如果是删除操作,Controller使用@DeleteMapping
区别:
@DateTimeFormat 属于org.springframework.format.annotation.DateTimeFormat,spring框架的注解 @JsonFormat 属于第三方com.fasterxml.jackson.annotation.JsonFormat; //jackson的注解 @JsonFormat一般用于对象的序列化和反序列化操作,使用的时候还要指定时区信息,@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") @DateTimeFormat 一般用于在springmvc中,前端使用表格传入参数到后台,进行时间的格式化的。
6.2、配置DELETE、PUT请求
web.xml的设置如下:
<filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
html的表单设置如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册</title> </head> <body> <form action="/del" method="post"> 编号:<input type="text" name="uid"/><br/> <input type="hidden" name="_method" value="DELETE" > <!--<input type="hidden" name="_method" value="PUT" >--> <input type="submit" value="注册"> </form> </body> </html>
6.3、后台与前端的对接
1、单个参数
@RequestParam 取值通道从form-data 或者是x-www-fomr-urlencodeed[url],请求头中取值
2、对象的入参
@RequestBody 取值通道从请求体中去拿
axios.get
axios.post
axios.put
axios.delete
get与delete一般传单个参数,写法一致
post与put一般是对象,写法一致
-
@RequestParam对应的前端
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>用户登陆</title> </head> <body> <div id="app"> <form> <input type="button" value="提交" @click="sub()" /> </form> </div> </body> <script src="./js/vue.min.js"></script> <script src="./js/axios.min.js"></script> <script type="text/javascript"> let data = "Hello, World!"; new Vue({ el: "#app", data: { newsTitle: "发射点发射点123" }, methods: { sub() { // axios.put("http://localhost:8080/news/update?newsTitle="+this.newsTitle) // .then(res => { // alert(res.data) // }) // url , data , params axios.put("http://localhost:8080/news/update", null, { params: { newsTitle: this.newsTitle } }) .then(res => { alert(res.data) }) } } }) </script> </html>
@ReuqstBody对应的前端
-
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>用户登陆</title> </head> <body> <div id="app"> <form> <input type="button" value="提交" @click="sub()" /> </form> </div> </body> <script src="./js/vue.min.js"></script> <script src="./js/axios.min.js"></script> <script type="text/javascript"> let data = "Hello, World!"; new Vue({ el: "#app", data: { newsTitle: "发射点发射点123" }, methods: { sub() { axios.put("http://localhost:8080/news/update",{newsTitle:this.newsTitle}) .then(res=>{ alert(res.data) }) } } }) </script> </html>
七、SSM框架的整合
1、mybatis框架:是数据访问层的解决方案。作用是操作数据库,实现实体与sql语句的映射,底层封装的jdbc。半自动化的ORM框架。(Spring-Templatejdbc)。
2、Spring框架:Spring的核心宗旨:不重复的造轮子,它是一个技术平台,也是一个生态环境。它对现如今所有流行的框架都做了整合。主要使用了IOC依赖注入与AOP的方式进行各种组件的注册与管理。mybatis-spring.jar包是mybatis所做得对spring整合的补丁包。
3、SpringMVC框架:是一个Spring对Servlet的一个封装,经典的Model2的实现,是一个基于模型与视图层的技术框架。
7.1 整合步骤
1、把所有的依赖导入项目
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.hxzy.ssm</groupId> <artifactId>ssm-demo-01</artifactId> <version>1.0</version> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.30</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.6</version> </dependency> <!--阿里巴巴的数据源连接池--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.8</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency> <!-- spring 操作jdbc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.8</version> </dependency> <!--AOP相关--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7.M3</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> <scope>provided</scope> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.0</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!--commonsupload上传组件--> <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency> </dependencies> </project>
2、依次填写各自的配置文件
applicationContext.xml
<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--mvc的注解驱动支持--> <mvc:annotation-driven /> <context:property-placeholder location="classpath:druid.properties"/> <!--数据源连接池--> <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${druid.driver}"/> <property name="url" value="${druid.url}"/> <property name="username" value="${druid.username}"/> <property name="password" value="${druid.password}"/> <property name="initialSize" value="${druid.pool.init}"/> <property name="minIdle" value="${druid.pool.minIdle}"/> <property name="maxActive" value="${druid.pool.maxActive}"/> <property name="maxWait" value="${druid.pool.maxWait}"/> </bean> <!--Spring注册SqlSessionFactory对象--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="druidDataSource"/> <property name="configLocation" value="classpath:mybatis-config.xml"/> </bean> <!-- 指定扫描基准包,把包下面面的接口注册成spring容器所管理的接口对象 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="cn.hxzy.mapper"/> </bean> <!-- 定义事务管理器--> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="druidDataSource"/> </bean> <!--启动事务的注解方式的支持--> <tx:annotation-driven transaction-manager="txManager"/> <!--扫描指定的基准包下,所有带注解的类,注册为bean实例,被spring容器进行管理--> <context:component-scan base-package="cn.hxzy"/> </beans>
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> <!--映射方式默认的自动映射关闭--> <setting name="autoMappingBehavior" value="PARTIAL"/> <!--mybatis的日志--> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <typeAliases> <package name="cn.hxzy.domain"/> </typeAliases> <!--映射器配置--> <mappers> <!--<mapper resource="mapper/NewsMapper.xml"/>--> <!--<mapper class="cn.hxzy.mapper.CategroyMapper"/>--> <!--<package name="cn.hxzy.mapper"/>--> </mappers> </configuration>
druid.properties
druid.driver=com.mysql.jdbc.Driver druid.url=jdbc:mysql://localhost:3306/news_db?serverTimezone=GMT%2B8&useUnicode=true&useSSL=false&characterEncoding=utf8 druid.username=root druid.password=root druid.pool.init=30 druid.pool.minIdle=30 druid.pool.maxActive=100 druid.pool.maxWait=10000
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--DispatherServlet--> <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> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-config.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
3、创建三层结构的项目
7.2 验证码的生成
验证码在web系统中的作用,防止恶意攻击。暴力破解软件。
生成验证码的方法:
1、使用第三方的组件,导入依赖
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.6.6</version> </dependency>
2、编写方法实现生成验证码
/生成验证码 io流-图片信息-二进制的数据-输出 @GetMapping("/getCode") public void getCode(HttpServletRequest request, HttpServletResponse response) { //通知浏览器端服务器要不使用缓存 response.setHeader("cache-control", "no-cache"); //立即生效 response.setHeader("expires", "0"); //生成验证码对象 1.宽度 2.高度 3.验证码位数 4.干扰点 CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(120, 40, 4, 20); //得到验证码 String code = captcha.getCode(); System.out.println("code:" + code); //1.保存在服务器端一份 2.返回给客户端一份 //redis 第三方缓存保存 HttpSessio0n session = request.getSession(); //使用session保存 session.setAttribute("code", code); OutputStream outputStream = null; try {0 outputStream = response.getOutputStream(); captcha.write(outputStream); } catch (IOException e) { e.printStackTrace(); } finally { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
3、编写登录的方法校验验证码
/** * 用户登录操作 * * @param userVo 用户登录vo实体对象 * @return success 代表成功,否则失败 */ @PostMapping("/login") public String login(@RequestBody UserVo userVo,HttpServletRequest request) { //业务,接收验证码 String result ="fail"; // 1.非空验证 String newCode = userVo.getCode(); if (StringUtils.isEmpty(newCode)) { return result; } // 2.和服务器端的验证码进行比对,一致,往下执行 HttpSession session = request.getSession(); Object code1 = session.getAttribute("code"); if(code1==null){ //postman工具调试,所以没有执行getCode,所以session就会为空 return result; } String oldCode = code1.toString(); if(StringUtils.equals(newCode,oldCode)){ result=userService.login(userVo.getUserNo(), userVo.getUserPwd()); } return result; }
4、前端页面的实现
说明:url:http://localhost:8080/getCode?" + Math.random() * 10;
如果是get请求,第二次请求与第一次请求的路径与参数都一致的话,服务器一般会调用缓存。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>用户登陆</title> </head> <body> <div id="app"> <form> <label>账号:</label><input type="text" placeholder="请输入手机号/邮箱" v-model="user.userNo" /><br /> <label>密码:</label><input type="password" placeholder="请输入密码" v-model="user.userPwd" /><br /> 验证码:<input id="code" type="text" v-model="user.code" /><img :src="imgUrl" /><br /> <input type="button" value="登录" @click="login()" /> </form> </div> </body> <script src="./js/vue.min.js"></script> <script src="./js/axios.min.js"></script> <script type="text/javascript"> axios.defaults.withCredentials = true new Vue({ el: "#app", data: { user: {}, imgUrl: "" }, mounted() { axios.get("http://127.0.0.1:8080/getCode?" + Math.random(), { responseType: 'blob' //二进制数据 }).then(res => { //createObjectURL方法会根据传入的参数创建一个指向该参数对象的URL. 这个URL的生命仅存在于它被创建的这个文档里 this.imgUrl = window.URL.createObjectURL(res.data); }) }, methods: { login() { axios.post("http://127.0.0.1:8080/login", this.user) .then(res => { alert(res.data) }) } } }) </script> </html>
7.3 md5加密
@Test public void test1(){ String pwd="123"; MD5 md5 = MD5.create(); String str = md5.digestHex(pwd+"^%$#@!ABC4234"); System.out.println(str); //202cb962ac59075b964b07152d234b70 }
八、 vue.js与axios.js进行文件或图片上传
步骤:
8.1、导入依赖
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency>
8.2、配置multipartResolver
上传文件的解析器
1024 b=1kb
1024KB=1MB
1024MB=1GB
1024GB=1TB
<!--切记:Spring是按照ID名称来进行装配的 CommonsMultipartResolver--> <!-- 在Spring配置文件中添加multipart配置 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 最大上传文件大小 --> <property name="maxUploadSize" value="10485760"/> <!-- 设置文件item的最大值 --> <property name="maxInMemorySize" value="4096"/> </bean>
8.3、前台页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>上传文件</title> </head> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <body> <div id="app"> <input type="file" @change="onFileChange" name="image" /> <button @click="uploadImage">上传图片</button> </div> <script src="./js/vue.min.js"></script> <script src="./js/axios.min.js"></script> <script type="text/javascript"> axios.defaults.withCredentials = true new Vue({ el: "#app", data: { selectedFile: null }, methods: { onFileChange(e) { this.selectedFile = e.target.files[0]; }, uploadImage() { const formData = new FormData(); formData.append('image', this.selectedFile); axios.post('http://127.0.0.1:8080/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' } }) .then(response => { console.log(response.data); }) .catch(error => { console.error(error); }); } } }) </script> </body> </html>
8.4、后台controller
package cn.hxzy.controller;/** @author:mengshujun @createTime: 2024-04-10 20:42:01 星期三 */ import org.apache.commons.io.FilenameUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.util.UUID; @RestController @CrossOrigin(value = {"http://127.0.0.1:8848"}, allowCredentials = "true") public class UploadController { @PostMapping(value = "upload") public String upload(@RequestParam("image") MultipartFile file){ //指定上传的路径 // String path = request.getServletContext().getRealPath("/upload"); String path = "E:/apache-tomcat-8.5.31/webapps/upload"; //上传文件的名称 String fileName = file.getOriginalFilename(); //得到扩展名 String exten = FilenameUtils.getExtension(fileName); //创建一个新的名称 String newFileName = UUID.randomUUID().toString().replaceAll("-", "")+"."+exten; File f=new File(path); if(!f.exists()){ f.mkdir();//创建upload文件夹 } try { file.transferTo(new File(f+"/"+newFileName)); return "success"; //纯服务器端的技术的话,返回逻辑视图名。 } catch (IOException e) { return "fail"; } } }
-