day13_MVC_前后端分离

day13_MVC_前后端分离

1MVC

1.1MVC是一种开发思想 把数据处理与视图显示分开

image-20250811101100172

注意:与后端代码三层结构是两种概念

MVC一般搭配JSP或者其他模板引擎技术使用

1.2JSP (java server page)

这个技术是为了简化servlet拼写页面而产生的

本质上还是servlet

xxxx.jsp 不能直接执行 需要经过 转换 编译才能运行

xxxx.jsp----->xxxx_jsp.java ------> xxxx_jsp.class

代码方式是java+html+css+js 代码结构比较混乱 后期维护更新很困难

使用方式 servlet+jsp

1.3跳转方式

转发

服务器内部跳转 地址栏停留在第一次请求上

req.setAttribute("msg","用户名或密码错误.....");
req.getRequestDispatcher("page/loginPage.jsp").forward(req,resp);

重定向

响应码302 带location响应头 浏览器会向location的地址重新发请求

resp.sendRedirect("page/loginPage.jsp");

image-20250811101501629

2前后端分离

2.1.ajax 异步请求技术 介绍

image-20250811105047674

2.2ajax代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <button onclick="sendAjax()">发送ajax请求...</button>
</body>
<script>
    const sendAjax = ()=>{
        //异步请求对象 简称为 xhr
        let xmlHttpRequest = new XMLHttpRequest();

        // 处理响应的函数 回调函数
        xmlHttpRequest.onreadystatechange = ()=>{
            if(xmlHttpRequest.readyState == 4 &&xmlHttpRequest.status == 200){
                console.log("处理数据....")
            }
        }

        xmlHttpRequest.open("POST","/xxx")
        xmlHttpRequest.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
        xmlHttpRequest.setRequestHeader("myHeader","jackrose")
        xmlHttpRequest.send("name=abc123&age=15")

        //location.href="/xxx"

    }


</script>
</html>

image-20250811112107966

2.3使用axios发送ajax请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <button onclick="sendAjax()">发送ajax请求...</button>
</body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
    const sendAjax = ()=>{
        //get请求
        //   请求方式  地址            参数
        axios.post("/day13/ajaxTest","name=jack")
            .then(resp=>{
                //内置对象 请求和响应状态参数
                console.log(resp)
                //响应体数据 直接解析json
                console.log(resp.data)
            })
        
        //post请求
       axios.get("/day13/ajaxTest?name=jack")
            .then(resp=>{
                //内置对象 请求和响应状态参数
                console.log(resp)
                //响应体数据 直接解析json
                console.log(resp.data)
            })

    }


</script>
</html>

2.4后端接口标准化

image-20250811161900293

接口代码格式
package com.javasm.controller;

import com.alibaba.fastjson.JSON;
import com.javasm.entity.Result;
import com.javasm.entity.ReturnCode;

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: RegNameServlet
 * @description:
 * @author: gfs
 * @date: 2025/8/11 14:38
 * @version: 0.1
 * @since: jdk17
 */
@WebServlet("/regName")
public class RegNameServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1接收请求数据
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("username");

        //2调用service
        //数据库里有jack

        //3根据不同的情况 做数据反馈
        /*


        http+json
        校验用户名是否重复接口

        接口文档 (说明文档)
        请求地址    /day13/regName
        请求参数    username  string  必填项
        支持请求方式 get/post
        返回数据类型 json
        返回数据示例
                   {code: 10000, msg: '用户名可用', returnData: 'green'}
                   {code: 10001, msg: '用户名不可用', returnData: 'red'}



        * 接口反馈数据的标准化
        * 1.响应头标记json格式
        *   resp.setContentType("application/json;charset=utf-8");
        * 2.通过统一工具转化 输出json格式字符串
        *   使用fastJSON转换 json格式字符串....
        * 3.通过实体类Result统一返回数据的key
        *       @Data
                //返回数据的实体类
                public class Result {
                    //返回操作码
                    private Integer code;
                    //返回操作描述
                    private String msg;
                    //返回附加数据
                    private Object returnData;

                }
           4.通过枚举 列举出操作码和操作信息的对应关系 减少笔误




        *
        * */
        //3.根据不同结果 返回不同的响应数据
        resp.setContentType("application/json;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        Result result = new Result();

        if("jack".equals(username)){
            //不可用
            //writer.print("{\"Msg\":\"用户名不可用\"}");
            result.setCode(ReturnCode.NAME_NO_OK.getCode());
            result.setMsg(ReturnCode.NAME_NO_OK.getMsg());
            result.setReturnData("red");
        }else{
            //可用
            //writer.print("{\"msg\":\"用户名可用\"}");
            result.setCode(ReturnCode.NAME_OK.getCode());
            result.setMsg(ReturnCode.NAME_OK.getMsg());
            result.setReturnData("green");
        }
        writer.print(JSON.toJSONString(result));
        writer.close();

    }
}

接口标准化

1.响应头标记json格式

resp.setContentType("application/json;charset=utf-8");

2.通过统一工具转化 输出json格式字符串

使用fastjson工具 统一返回json格式字符串

import com.alibaba.fastjson.JSON;
import com.javasm.entity.ClassInfo;
import com.javasm.entity.Person;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @className: JSONTest
 * @description:
 * @author: gfs
 * @date: 2025/8/11 14:50
 * @version: 0.1
 * @since: jdk17
 */
public class JSONTest {



    @Test
    public void myJsonTest(){
        //java中的数据   实体对象  集合   list   map
        //json格式字符串  json + 数组
        /*
        * Gson      google的转换jar包  大而全 转换效率较低  api复杂
        * jackson   外国常用转换jar包   大而全             api较简单
        * fastjson  alibabajar包            转换最快     api简单
        *
        *
        * JSON.toJSONString(person)                 java对象 转 json字符串
        * JSON.parseObject(jsonStr, Person.class)   json字符串 转 指定java对象
        *
        * 常用的数据格式
        * 1 单个对象
        * 2 对象集合
        * 3 对象包含集合 混合使用
        * 4 map可以自定义键值对传值 尽量少用(临时性强)
        * */

//        Person person = new Person(1,"jack",15);
        //支持任意对象 需要转换数据是 直接传给fastjson 转成json字符串
//        String jsonString = JSON.toJSONString(person);
//        System.out.println(jsonString);
//        String jsonStr = "{\"age\":15,\"id\":1,\"name\":\"rose\"}";
//        Person person = JSON.parseObject(jsonStr, Person.class);
//        System.out.println(person);
//        List<Person> listPerson = new ArrayList<>();
//        listPerson.add(new Person(1,"jack",15));
//        listPerson.add(new Person(2,"jack2",15));
//        listPerson.add(new Person(3,"jack3",15));
//
//        String jsonString = JSON.toJSONString(listPerson);
//        System.out.println(jsonString);

//        ClassInfo classInfo = new ClassInfo();
//        classInfo.setClassName("张三的班");
//        classInfo.setClassAddr("枫杨街");
//        classInfo.setTeacher(new Person(0,"张三",55));
//        List<Person> students = new ArrayList<>();
//        students.add(new Person(1,"罗翔1",15));
//        students.add(new Person(2,"罗翔2",15));
//        students.add(new Person(3,"罗翔3",15));
//        classInfo.setStudents(students);

        HashMap<String, Object> dataMap = new HashMap<>();
        dataMap.put("className","李四的班");
        dataMap.put("teacher",new Person(0,"李四",55));
        List<Person> students = new ArrayList<>();
        students.add(new Person(1,"罗翔1",15));
        students.add(new Person(2,"罗翔2",15));
        students.add(new Person(3,"罗翔3",15));
        dataMap.put("students",students);

        System.out.println( JSON.toJSONString(dataMap));


    }
}

3.通过实体类Result统一返回数据的key

package com.javasm.entity;

import lombok.Data;

/**
 * @className: Result
 * @description:
 * @author: gfs
 * @date: 2025/8/11 15:27
 * @version: 0.1
 * @since: jdk17
 */
@Data
//返回数据的实体类
public class Result {
    //返回操作码
    private Integer code;
    //返回操作描述
    private String msg;
    //返回附加数据
    private Object returnData;

}

4.通过枚举 列举出操作码和操作信息的对应关系

package com.javasm.entity;

import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;

/**
 * @className: ReturnCode
 * @description:
 * @author: gfs
 * @date: 2025/8/11 15:37
 * @version: 0.1
 * @since: jdk17
 */
@NoArgsConstructor
@Getter
public enum ReturnCode {
    NAME_OK(10000,"用户名可用"),
    NAME_NO_OK(10001,"用户名不可用");

    private Integer  code;
    private String   msg;

    private ReturnCode(Integer  code,String msg){
        this.code = code;
        this.msg = msg;
    }

}

2.5接口测试工具

使用独立接口测试工具 方便保存测试案例

image-20250811160847588

3前端导入axios 发送ajax请求

1安装axios

pnpm add axios

2跨域请求

 跨域(domain)请求
 当产生了 从一个网站 访问另一个网站数据 会出现跨域请求 CORS 会通知浏览器做访问限制
 默认不然产生跨域数据访问
 符合CORS 在服务端 设置允许访问

 浏览器对跨域的限定
    http:// 127.0.0.1 :  8080
    协议     地址        端口号
    浏览器自动发送预检请求 method options 检测响应头 是否符合CORS要求 
    通过后会缓存一定事件 

符合CORS策略的代码 需要在被访问端(服务器端 ) 添加响应头设置

        //允许跨域访问暂时写在公共⽗类中
        // /* 允许跨域的主机地址*/
        resp.setHeader("Access-Control-Allow-Origin", "http://localhost:5173");
        /* 允许跨域的请求⽅法GET, POST, HEAD 等*/
        resp.setHeader("Access-Control-Allow-Methods", "*");
        /* 重新预检验跨域的缓存时间(s) */
        resp.setHeader("Access-Control-Max-Age", "3600");
        /* 允许跨域的请求头*/
        resp.setHeader("Access-Control-Allow-Headers", "*");
        /* 是否携带cookie */
        resp.setHeader("Access-Control-Allow-Credentials", "true");

3 对aixos进行二次封装

image-20250811172143171

import axios from 'axios'

//固定url前缀
axios.defaults.baseURL = 'http://localhost:8080/day13';
//post请求 自己带请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

//get post 请求统一结构 (地址,数据使用json对象)
const myPost = (url,params)=>{
    return axios({
        method: 'post',
        url: url,
        data: params
      });

} 

const myGet = (url,params)=>{
    return axios({
        method: 'post',
        url: url,
        params: params
      });
} 


export {myGet,myPost}

4前后端联调

login.vue

<template>
    <el-card class="loginPanel" style="max-width: 399px">
        <template #header>
            <div class="card-header">
                <img src="../assets/login.png"/>
            </div>
        </template>

        <el-form ref="formRef" hide-required-asterisk :rules="rules" :model="loginForm" label-width="60" style="max-width: 380px">
            <el-form-item label="用户名" prop="username">
                <el-input v-model="loginForm.username" :suffix-icon="User"/>
            </el-form-item>
            <el-form-item label="密码" prop="password">
                <el-input type="password" show-password v-model="loginForm.password" :suffix-icon="Lock" />
            </el-form-item>

            <el-form-item>
                <el-button plain color="#626aef" @click="loginSubmit">登录</el-button>
                <el-button plain color="#626aef" @click="loginReset">重置</el-button>
            </el-form-item>
        </el-form>


    </el-card>
</template>

<script setup>
import { ref, reactive, onMounted } from 'vue'
import { Check, Delete, Edit, Message, Search, Star, Share,User,Lock } from '@element-plus/icons-vue'
import router from '@/router'
import { ElMessage,ElMessageBox  } from 'element-plus'

import {myGet,myPost} from '@/myaxios'


const formRef = ref()

const loginReset = ()=>{
    formRef.value.resetFields()
}
const loginSubmit = ()=>{
    formRef.value.validate((valid,fields)=>{
        if(valid){
            console.log("提交表单数据",loginForm);
            myGet("/login",loginForm)
            .then(resp=>{
                if(resp.data.code == 10010){
                    ElMessage.success(resp.data.msg)
                    router.push("/main")
                }else if(resp.data.code == 10011){
                    ElMessage.error(resp.data.msg)
                }
                
            })
           

        }
    })
}

const rules = reactive({
    username: [
        { required: true, message: '请输入用户名', trigger: 'blur' },
    ],
    password:[
        { required: true, message: '请输入密码', trigger: 'blur' },
        { min: 4, max: 8, message: '长度4-8位之间', trigger: 'blur' },
    ]
})


const loginForm = reactive({
    username:'',
    password:''
})

/*
 跨域(domain)请求
 当产生了 从一个网站 访问另一个网站数据 会出现跨域请求 CORS 会通知浏览器做访问限制
 默认不然产生跨域数据访问
 符合CORS 在服务端 设置允许访问

 浏览器对跨域的限定
    http:// 127.0.0.1 :  8080
    协议     地址        端口号
    浏览器自动发送预检请求 method options 检测响应头 是否符合CORS要求 
    通过后会缓存一定事件 




*/


// onMounted(()=>{
//     myGet("/login",{username:'aa',password:'bbb'})
    
// })



</script>

<style scoped>
/* scoped只对当前vue文件生效  */

.loginPanel {
    margin: 300px auto;
    background-color: rgba(219, 219, 219, 0.541);
}
</style>

loginServlet.java

package com.javasm.controller;

import com.alibaba.fastjson.JSON;
import com.javasm.entity.Result;
import com.javasm.entity.ReturnCode;
import com.javasm.entity.User;
import com.javasm.service.UserService;
import com.javasm.service.impl.UserServiceImpl;

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: LoginServlet
 * @description:
 * @author: gfs
 * @date: 2025/8/11 16:29
 * @version: 0.1
 * @since: jdk17
 */
@WebServlet("/login")
public class LoginServlet extends HttpServlet {



    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //允许跨域访问暂时写在公共⽗类中
        // /* 允许跨域的主机地址*/
        resp.setHeader("Access-Control-Allow-Origin", "http://localhost:5173");
        /* 允许跨域的请求⽅法GET, POST, HEAD 等*/
        resp.setHeader("Access-Control-Allow-Methods", "*");
        /* 重新预检验跨域的缓存时间(s) */
        resp.setHeader("Access-Control-Max-Age", "3600");
        /* 允许跨域的请求头*/
        resp.setHeader("Access-Control-Allow-Headers", "*");
        /* 是否携带cookie */
        resp.setHeader("Access-Control-Allow-Credentials", "true");





        //1接收请求参数 转换格式 封装对象
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        //2调用service
        UserService userService = new UserServiceImpl();
        User loginUser = userService.login(username, password);
        //3根据执行结果 返回json数据
        Result result = new Result();
        if(loginUser!=null){
            result.setCode(ReturnCode.LOGIN_SUCCESS.getCode());
            result.setMsg(ReturnCode.LOGIN_SUCCESS.getMsg());
        }else{
            result.setCode(ReturnCode.LOGIN_FAILED.getCode());
            result.setMsg(ReturnCode.LOGIN_FAILED.getMsg());
        }
        //设置输出流
        resp.setContentType("application/json;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        writer.print(JSON.toJSONString(result));
        writer.close();

    }
}

1.会写后端服务接口 注册接口 用户列表接口

2.会用post测试接口

3.写对应的页面 并前后端联调 注意跨域请求设置 和axios请求的使用

posted @ 2025-08-16 15:31  小胡coding  阅读(12)  评论(0)    收藏  举报