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原生代码

页面




    
    Title


    

<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.responseText
                console.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>

服务端

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 {
​
    @Override
    protected 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'
  }
});

校验用户名重复示例

页面




    
    Title


    
   
   
<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> ​

服务端

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 {
​
    @Override
    protected 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 {

    @Override
    protected 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 {

    @Override
    protected 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调用service
        AreaService areaServce = new AreaServceImpl();
        List 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 {

    @Override
    public List 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 {

    @Override
    public List listAreaByParentCode(Integer parentCode) {
        //jdbc 流程比较繁琐
        List 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;

}

写完接口后 使用接口测试工具 测试接口的使用

posted @ 2025-11-19 17:23  gccbuaa  阅读(6)  评论(0)    收藏  举报