day13_mvc 前后端分离
day13_mvc 前后端分离
1MVC
model (数据)模型
view 视图
control 控制
servlet+jsp 用jsp做view
如果需要数据
页面跳转
1请求转发
请求对象调用
一次请求
借助request对象 可以传任意类型
2响应重定向
响应对象调用
多次请求
只能传字符的简单数据
2前后端分离
前端 html css javascript
通过ajax请求(前端技术 发送请求的技术) 交互数据
后端 java
2.1ajax技术介绍
* ajax核心功能* 页面不跳转的前提下 发请求与后端做数据交互* 1.ajax通过子线程发送请求* 2.报文结构相同 后端处理模式不变* 3.后端会有一定的变化* 1.后端不再传页面标签 只传处理结果* 2.重定向功能无效* 3.请求转发(功能削弱 很少用到)*** 前端使用vue框后 使用MVVM模式
2.2ajax原生代码
页面
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><button onclick="myHref()">发送ajax</button> </body> <script>/** ajax核心功能* 页面不跳转的前提下 发请求与后端做数据交互* 1.ajax通过子线程发送请求* 2.报文结构相同 后端处理模式不变* 3.后端会有一定的变化* 1.后端不再传页面标签 只传处理结果* 2.重定向功能无效* 3.请求转发(功能削弱 很少用到)*** 前端使用vue框后 使用MVVM模式*** */ const myHref = ()=>{//异步请求对象let xhr = new XMLHttpRequest();//1配置回调函数xhr.onreadystatechange = ()=>{if(xhr.readyState == 4 && xhr.status == 200){//请求正常 响应正常let respData = xhr.responseTextconsole.log(respData)//可以根据响应情况 写不同js处理//......}}//2.设置请求参数xhr.open("post","/day13/ajaxDemo")//3.设置请求头xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");xhr.setRequestHeader("myHeader","jack123")//4.发送请求xhr.send("username=rose&age=15"); } </script> </html>
服务端
package com.javasm; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /*** @className: AjaxDemoServlet* @author: gfs* @date: 2025/10/17 10:59* @version: 0.1* @since: jdk17* @description:*/ @WebServlet("/ajaxDemo") public class AjaxDemoServlet extends HttpServlet { @Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//取请求参数System.out.println(req.getParameter("username"));//取请求头String myHeader = req.getHeader("myHeader");System.out.println(myHeader); //通过输出流 返回数据resp.setContentType("text/html;charset=utf-8");PrintWriter writer = resp.getWriter();writer.print("name ok!!!");writer.close(); } }
2.3axios 简化ajax请求
https://www.axios-http.cn/docs/intro axios官网
简化后的ajax请求
get请求
axios.get('/day13/ajaxDemo?username=rose').then((resp)=>{//请求响应数据对象console.log(resp)//返回的实际数据console.log(resp.data)})
post请求
axios.post('/day13/ajaxDemo','username=rose').then((resp)=>{//请求响应数据对象console.log(resp)//返回的实际数据console.log(resp.data)})
请求格式:
//用来配置请求的其他参数axios.post('/day13/ajaxDemo','username=rose',{headers: {'myHeader': 'zhangsan'},})//写成功的回调.then((resp)=>{//请求响应数据对象console.log(resp)//返回的实际数据console.log(resp.data)})//写失败的回调.catch(function (error) {// 处理错误情况console.log(error);})//不管成功失败.finally(function () {// 总是会执行});
原始请求格式 全用json配置
// 发起一个post请求 //全部用json做配置 axios({method: 'post',url: '/user/12345',data: {firstName: 'Fred',lastName: 'Flintstone'} });
校验用户名重复示例
页面
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><input id="username" type="text" placeholder="username" onchange="checkName()"><span id="checkNameSpan"></span><br/><input type="text" placeholder="mail"><br/><input type="text" placeholder="phone"><br/> </body> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script>const checkName = ()=>{let currentName = document.getElementById("username").value//vue 依赖 插件axios.post("/day13/checkName","username="+currentName).then(resp=>{console.log(resp.data)if(resp.data){document.getElementById("checkNameSpan").innerHTML = "用户名可用"}else{document.getElementById("checkNameSpan").innerHTML = "用户名重复"}}) } </script> </html>
服务端
package com.javasm; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /*** @className: CheckNameServlet* @author: gfs* @date: 2025/10/17 11:48* @version: 0.1* @since: jdk17* @description:*/ @WebServlet("/checkName") public class CheckNameServlet extends HttpServlet { @Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("utf-8");String username = req.getParameter("username");String respData = "";if("jack".equals(username)){//重复respData = "false";}else{//可用respData = "true";} resp.setContentType("text/html;charset=utf-8");PrintWriter writer = resp.getWriter();writer.print(respData);writer.close(); } }
3后端接口标准化
后端针对ajax请求和前后端分离 需要做一些代码格式的标准化
* 1.三层结构* 2.servlet做控制层* 3.数据返回json* 可以返回多维度数据 和复杂的数据结构* resp.setContentType("application/json;charset=utf-8")* 4.使用统一的转换jar包* json与java对象互相转换* Gson google的 功能大而全 api较复杂 转换效率偏慢* Jackson 功能大而全 转换效率偏慢 api较简单* Fastjson 功能较全 转换块 api简单* 验证json字符串的网站 https://www.json.cn/* 使用fastjson (标准json格式 需要key带引号)* JSON.toJSONString(对象) 对象 转json字符串* User user2 = JSON.parseObject(myJsonStr, User.class) 字符串 转java对象** 5.统一返回数据的key* ReturnResult* 操作码 code 操作信息 msg 附加数据(详细信息) returnData** 6.通过枚举类 列举操作与操作信息的对应关系* 防止程序员手误 导致操作码错乱
package com.javasm;import com.alibaba.fastjson.JSON; import com.javasm.entity.ReturnCode; import com.javasm.entity.ReturnResult;import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter;/*** @className: CheckNameServlet* @author: gfs* @date: 2025/10/17 11:48* @version: 0.1* @since: jdk17* @description:*/ @WebServlet("/checkName") public class CheckNameServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {/** 后端只提供数据处理服务* (后端是远程调用的方法)* 代码格式做标准化***** 1.三层结构* 2.servlet做控制层* 3.数据返回json* 可以返回多维度数据 和复杂的数据结构* resp.setContentType("application/json;charset=utf-8")* 4.使用统一的转换jar包* json与java对象互相转换* Gson google的 功能大而全 api较复杂 转换效率偏慢* Jackson 功能大而全 转换效率偏慢 api较简单* Fastjson 功能较全 转换块 api简单* 验证json字符串的网站 https://www.json.cn/* 使用fastjson (标准json格式 需要key带引号)* JSON.toJSONString(对象) 对象 转json字符串* User user2 = JSON.parseObject(myJsonStr, User.class) 字符串 转java对象** 5.统一返回数据的key* ReturnResult* 操作码 code 操作信息 msg 附加数据(详细信息) returnData** 6.通过枚举类 列举操作与操作信息的对应关系* 防止程序员手误 导致操作码错乱*** */req.setCharacterEncoding("utf-8");String username = req.getParameter("username");//String respData = "";ReturnResult returnResult = new ReturnResult();if("jack".equals(username)){//重复returnResult.setCode(ReturnCode.NAMECHECK_FAILED.getCode());returnResult.setMsg(ReturnCode.NAMECHECK_FAILED.getMsg());returnResult.setReturnData("red");//respData = "{\"msg\":\"用户名重复\",\"color\":\"red\"}";}else{//可用returnResult.setCode(ReturnCode.NAMECHECK_OK.getCode());returnResult.setMsg(ReturnCode.NAMECHECK_OK.getMsg());returnResult.setReturnData("green");//respData = "{\"msg\":\"用户名可用\",\"color\":\"green\"}";}resp.setContentType("application/json;charset=utf-8");PrintWriter writer = resp.getWriter();writer.print(JSON.toJSONString(returnResult));writer.close();} }
接口文档:
前后端可以根据接口文档做开发 是前后端交互的重要文档
* 后端服务接口* 校验用户名是否重复接口* 接口文档* 请求地址 /day13/checkName* 请求方式 get/post* 请求参数 username string* 返回数据格式 json* 返回数据示例* 重复* {code: 10011,msg: "用户名重复",returnData: "red"}* 可用{code: 10010,msg: "用户名可用",returnData: "green"}
4前端使用独立的服务器 vite
注意:
axios与vue没有集成关系 不是vue插件 是普通依赖
安装
pnpm add axios
哪个页面使用 就在那个页面引入
import axios from 'axios' axios.get("/xxx")
跨域请求异常情况:
//跨域问题://从服务器A 直接访问服务器B 浏览器会做限制//浏览器自动发送预检请求 检查请求是否出自同源 method=options
解决方法 符合cors标准
配置CORS 符合浏览器的CORS 规范被访问端配置 允许访问的来源
/* 允许跨域的主机地址*/resp.setHeader("Access-Control-Allow-Origin", "http://localhost:5173");/* 允许跨域的请求⽅法GET, POST, HEAD 等*/resp.setHeader("Access-Control-Allow-Methods", "*");/*重新预检验跨域的缓存时间*/resp.setHeader("Access-Control-Max-Age", "3600");/* 允许跨域的请求头 */resp.setHeader("Access-Control-Allow-Headers", "*");/* 是否携带cookie */resp.setHeader("Access-Control-Allow-Credentials", "true");
接口例子2 省市县信息
数据库表
查询省市县信息的sql语句
select * from tb_area where parent_code = 1001
查询省市县接口
controller
package com.javasm.controller;import com.alibaba.fastjson.JSON; import com.javasm.entity.AreaInfo; import com.javasm.entity.ReturnCode; import com.javasm.entity.ReturnResult; import com.javasm.service.AreaService; import com.javasm.service.impl.AreaServceImpl;import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.List;/*** @className: ListAreaServlet* @author: gfs* @date: 2025/10/17 16:47* @version: 0.1* @since: jdk17* @description:*/ @WebServlet("/listArea") public class ListAreaServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {/* 查询地区信息接口* 接口文档* 请求地址 /day13/listArea* 请求方式 get/post* 请求参数 parentCode int 必填 非必填项* 必须要传值 有默认值* 返回数据格式 json* 返回数据示例*//* 允许跨域的主机地址*/resp.setHeader("Access-Control-Allow-Origin", "http://localhost:5173");/* 允许跨域的请求⽅法GET, POST, HEAD 等*/resp.setHeader("Access-Control-Allow-Methods", "*");/*重新预检验跨域的缓存时间*/resp.setHeader("Access-Control-Max-Age", "3600");/* 允许跨域的请求头 */resp.setHeader("Access-Control-Allow-Headers", "*");/* 是否携带cookie */resp.setHeader("Access-Control-Allow-Credentials", "true");//1接收请求参数 转换格式 封装对象String parentCodeStr = req.getParameter("parentCode");Integer parentCode = 0;//没有key null 有key 没值 ""if(parentCodeStr!=null&&!"".equals(parentCodeStr)){parentCode = Integer.parseInt(parentCodeStr);}//2调用serviceAreaService areaServce = new AreaServceImpl();List<AreaInfo> areaInfos = areaServce.listAreaByParentCode(parentCode);//3根据执行结果 返回json数据ReturnResult returnResult = new ReturnResult(ReturnCode.QUERY_SUCCESS.getCode(),ReturnCode.QUERY_SUCCESS.getMsg(),areaInfos);resp.setContentType("application/json;charset=utf-8");PrintWriter writer = resp.getWriter();writer.print(JSON.toJSONString(returnResult));writer.close();} }
service
package com.javasm.service.impl;import com.javasm.dao.impl.AreaDaoImpl; import com.javasm.entity.AreaInfo; import com.javasm.service.AreaService;import java.util.List;/*** @className: AreaServceImpl* @author: gfs* @date: 2025/10/17 16:58* @version: 0.1* @since: jdk17* @description:*/ public class AreaServceImpl implements AreaService {@Overridepublic List<AreaInfo> listAreaByParentCode(Integer parentCode) {return new AreaDaoImpl().listAreaByParentCode(parentCode);} }
dao
package com.javasm.dao.impl;import com.javasm.dao.AreaDao; import com.javasm.entity.AreaInfo; import com.javasm.entity.User;import java.sql.*; import java.util.ArrayList; import java.util.List;/*** @className: AreaDaoImpl* @author: gfs* @date: 2025/10/17 16:52* @version: 0.1* @since: jdk17* @description:*/ public class AreaDaoImpl implements AreaDao {@Overridepublic List<AreaInfo> listAreaByParentCode(Integer parentCode) {//jdbc 流程比较繁琐List<AreaInfo> listArea = new ArrayList<>();Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;try {//1 创建连接//加载驱动Class.forName("com.mysql.cj.jdbc.Driver");//创建连接connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mydb", "root", "root");//2准备请求数据请求String sql = "select * from tb_area where parent_code = ?";preparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1,parentCode);//3发送请求 接收反馈resultSet = preparedStatement.executeQuery();//4读取响应报文中的数据内容 做成java中的对象数据while(resultSet.next()){int areaCode = resultSet.getInt("area_code");String areaName = resultSet.getString("area_name");String parentCodeDB = resultSet.getString("parent_code");listArea.add(new AreaInfo(areaCode,areaName,parentCode)) ;}} catch (ClassNotFoundException e) {throw new RuntimeException(e);} catch (SQLException e) {throw new RuntimeException(e);}finally {try{if(resultSet!=null)resultSet.close();if(preparedStatement!=null)preparedStatement.close();if(connection!=null)connection.close();} catch (SQLException e) {throw new RuntimeException(e);}}return listArea;} }
entity
package com.javasm.entity;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;/*** @className: AreaInfo* @author: gfs* @date: 2025/10/17 16:50* @version: 0.1* @since: jdk17* @description:*/ @Data @AllArgsConstructor @NoArgsConstructor public class AreaInfo {private Integer areaCode;private String areaName;private Integer parentCode;}
写完接口后 使用接口测试工具 测试接口的使用