• 【无标题】


    基于Vue+ElementPlus+Servlet实现前后段分离的学生管理系统

    零、系统介绍及其项目全套代码

    系统介绍

    基于Vue+ElementPlus+Servlet实现前后段分离的学生管理系统
    前段所用技术:Vue3+ElementPlus
    后端所用技术:mysql+JDBC+Tomcat+Servlet+Druid数据库连接池
    实现的功能有:学生的新增、学生的修改、学生数据的回显、学生数据的删除

    项目全套代码

    链接地址:https://download.csdn.net/download/weixin_46411355/86719910

    一、前段

    1.搭建vue-cli+axios+ElementPlus脚手架

    此处省略,可参考我的另一篇博客——《安装node.js后进行的操作(配置node环境变量、npm镜像加速、安装vue-cli项目脚手架、在IDEA中打开并运行脚手架、安装ElementPlus、新建路由)》
    博客链接https://huanghaoheng.blog.csdn.net/article/details/126821977

    2.安装vue-axios依赖,并导入axios和vue-axios,同时修改main.js代码

    2.1 安装vue-axios依赖

    win+R打开运行框,输入cmd,回车
    在这里插入图片描述
    在DOS窗口输入vue ui回车
    在这里插入图片描述

    打开浏览器输入地址:localhost:8080
    弹出以下界面,点击依赖 => 点击添加依赖

    在这里插入图片描述
    搜索vue-axios依赖–>点击–>点击安装
    在这里插入图片描述
    弹出以下页面说明安装完成
    在这里插入图片描述

    2,2导入axios和vue-axios,同时修改main.js代码

    在这里插入图片描述

    main.js代码如下

    import {createApp} from 'vue'
    import App from './App.vue'
    import router from './router'
    import store from './store'
    
    import ElementPlus from 'element-plus'
    import 'element-plus/dist/index.css'
    
    import axios from 'axios'
    import VueAxios from 'vue-axios'
    
    export const app = createApp(App)
    
    app.use(store)
        .use(router)
        .use(VueAxios, axios)
        .use(ElementPlus).mount('#app')
    

    3. 测试请求是否发送成功

    在main.js发送请求

    import {createApp} from 'vue'
    import App from './App.vue'
    import router from './router'
    import store from './store'
    
    import ElementPlus from 'element-plus'
    import 'element-plus/dist/index.css'
    
    import axios from 'axios'
    import VueAxios from 'vue-axios'
    
    export const app = createApp(App)
    
    app.use(store)
        .use(router)
        .use(VueAxios, axios)
        .use(ElementPlus).mount('#app')
    
    
    /*
    *then是回调 后台返回的数据 就会被response对象接收
    */
    app.axios.get("http://localhost:9090/student").then((response) => {
        console.log(response.data)
    })
    

    npm installnpm run serve启动项目,具体如何操作可参考我的另一篇博客(博客链接:https://huanghaoheng.blog.csdn.net/article/details/126821977
    打开浏览器按F12访问,localhost:8080,如果在Network中有student则发送的测试请求成功
    在这里插入图片描述

    4.解决前后段跨域问题

    在这里插入图片描述
    将以下代码复制到Servlet中的service方法里面

    //        resp.addHeader("Access-Control-Allow-Origin", "*");
            resp.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");//只允许localhost:8080访问我
           
            resp.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
            
    //        resp.addHeader("Access-Control-Allow-Headers", "Content-Type");
            resp.addHeader("Access-Control-Allow-Headers", "*");//所有的格式
            
             resp.addHeader("Access-Control-Max-Age", "3600");//访问的超时时间多少毫秒
    

    在这里插入图片描述
    再次在浏览器中访问localhost:8080看到student不飘红,预览有数据,则证明跨域问题解决成功
    在这里插入图片描述
    在这里插入图片描述

    5.新建一个Student的路由

    可以参考我之前分享的链接博客中的“六、新建路由”创建。博客链接https://huanghaoheng.blog.csdn.net/article/details/126821977
    也可以跟着笔者的下述步骤创建

    5.1 在App.vue中注册Student路由组件

    在这里插入图片描述
    供读者复制粘贴的代码
    App.vue文件

    <template>
      <nav>
        <router-link to="/">Home</router-link> |
        <router-link to="/about">About</router-link> |
        <router-link to="/student">Student</router-link> |
      </nav>
      <router-view/>
    </template>
    
    <style lang="stylus">
    #app
      font-family Avenir, Helvetica, Arial, sans-serif
      -webkit-font-smoothing antialiased
      -moz-osx-font-smoothing grayscale
      text-align center
      color #2c3e50
      margin-top 60px
    </style>
    
    5.2在router文件夹下的index,js里面配置路由表中路由和其对应的组件View视图

    在这里插入图片描述
    供读者复制粘贴的代码
    router下的index,js文件

    import { createRouter, createWebHashHistory } from 'vue-router'
    import HomeView from '../views/HomeView.vue'
    
    const routes = [
      {
        path: '/',
        name: 'home',
        component: HomeView
      },
      {
        path: '/about',
        name: 'about',
        // route level code-splitting
        // this generates a separate chunk (about.[hash].js) for this route
        // which is lazy-loaded when the route is visited.
        component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
      },
      {
        path: '/student',
        name: 'student',
        // route level code-splitting
        // this generates a separate chunk (about.[hash].js) for this route
        // which is lazy-loaded when the route is visited.
        component: () => import( '../views/StudentView.vue')
      }
    ]
    
    const router = createRouter({
      history: createWebHashHistory(),
      routes
    })
    
    export default router
    
    5.3在views里面创建StudentView

    在这里插入图片描述
    供读者复制粘贴的代码
    StudentView.vue文件

    <template>
      <div class="student">
        <Student/>
      </div>
    </template>
    
    <script>
    // @ is an alias to /src
    import Student from '@/components/Student.vue'
    
    export default {
      name: 'StudentView',
      components: {
        Student
      }
    }
    </script>
    
    5.4.在components中创建Student组件

    在这里插入图片描述

    在这里插入图片描述

    供读者复制粘贴的代码
    Student.Vue文件(页面的测试数据,后期对接Servlet后会做修改)

    <template>
        <el-table :data="tableData" style="width: 100%">
            <el-table-column prop="date" label="Date" width="150" />
            <el-table-column prop="name" label="Name" width="120" />
            <el-table-column prop="state" label="State" width="120" />
            <el-table-column prop="city" label="City" width="120" />
            <el-table-column prop="address" label="Address" width="600" />
            <el-table-column prop="zip" label="Zip" width="120" />
            <el-table-column fixed="right" label="Operations" width="120">
                <template #default>
                    <el-button link type="primary" size="small" @click="handleClick"
                    >Detail</el-button
                    >
                    <el-button link type="primary" size="small">Edit</el-button>
                </template>
            </el-table-column>
        </el-table>
    </template>
    
    <script>
    
        export default {
            data(){
                return{
                    tableData:[
                        {
                            date: '2016-05-03',
                            name: 'Tom',
                            state: 'California',
                            city: 'Los Angeles',
                            address: 'No. 189, Grove St, Los Angeles',
                            zip: 'CA 90036',
                            tag: 'Home',
                        },
                        {
                            date: '2016-05-02',
                            name: 'Tom',
                            state: 'California',
                            city: 'Los Angeles',
                            address: 'No. 189, Grove St, Los Angeles',
                            zip: 'CA 90036',
                            tag: 'Office',
                        },
                        {
                            date: '2016-05-04',
                            name: 'Tom',
                            state: 'California',
                            city: 'Los Angeles',
                            address: 'No. 189, Grove St, Los Angeles',
                            zip: 'CA 90036',
                            tag: 'Home',
                        },
                        {
                            date: '2016-05-01',
                            name: 'Tom',
                            state: 'California',
                            city: 'Los Angeles',
                            address: 'No. 189, Grove St, Los Angeles',
                            zip: 'CA 90036',
                            tag: 'Office',
                        },
                    ]
                }
            }
        }
    </script>
    
    看后端到步骤5项目目录结构创建*

    此时,后端 应该做到 步骤5项目目录结构创建
    此时npm installnpm run serve运行前段程序,同时后段运行tomcat服务器,再浏览中访问localhost:8080,点击Student路由,展示效果如下
    在这里插入图片描述

    6.前端发送axios请求,并渲染数据

    结果
    6.1 创建并封装前段请求

    zho在这里插入图片描述

    HttpRequest.js文件
    供读者复制粘贴的代码

    import axios from 'axios'
    import Qs from 'qs'
    
    
    export function request(requestConfig) {
    
        // axios 实例
        const instance = axios.create({
            baseURL: 'http://localhost:9090/',
            timeout: 2000,
            transformRequest: [function (data) {
                // 对 data 进行任意对转换
                return Qs.stringify(data);
            }],
        });
    
        //  请求拦截器
        instance.interceptors.request.use(function (config) {
            // Do something before request is sent
            return config;
        }, function (error) {
            // Do something with request error
            return Promise.reject(error);
        });
    
        // 响应拦截器
        instance.interceptors.response.use(function (response) {
            // Do something with response data
    
            return response.data;
        }, function (error) {
            // Do something with response error
            return Promise.reject(error);
        });
    
        return instance(requestConfig);
    
    }
    

    StudentHttpRequest.js文件
    供读者复制粘贴的代码

    import {request} from '@/request/HttpRequest';
    
    //查询学生列表信息
     export function selectStudentList() {
         var requestConfig = {
             url:"/student",
             method:"get"
         }
         return request(requestConfig);
     }
    
    6.2.页面学生表格数据渲染

    Student.vue文件
    供读者复制粘贴的代码

    <!-- 展示的学生信息列表   -->
        <el-table :data="tableData" style="width: 100%" stripe>
            <el-table-column prop="name" label="姓名" width="250"/>
            <el-table-column prop="age" label="年龄" width="250"/>
            <el-table-column prop="gender" label="性别" width="250">
                <template #default="scope">{{scope.row.gender?'男':'女'}}
            </el-table-column>
    
            <el-table-column prop="createTime" label="创建时间" width="250"/>
            <el-table-column fixed="right" label="操作" width="250">
                <template #default="scope">
                    <el-button link type="primary" size="small" @click="editById(scope.row)">编辑</el-button>
                    <el-button link type="primary" size="small" @click="deleteById(scope.row)">删除</el-button>
                </template>
            </el-table-column>
        </el-table>
    </template>
    
    
    <script >
        import {selectStudentList} from '@/request/studentHttpRequest'
        export default {
            data() {
                return {
                    tableData:[]
                }
            },
            created(){
                this.showStudentList();
            },
            methods:{
                // 自定义一个查询方法
                showStudentList(){
    
                    selectStudentList().then(response=>{
                        this.tableData = response;
                    }).catch(function (error) {
                        console.log(error);
                    })
                }
            }
        }
    
    </script>
    
    过程:由简单到难

    在created()方法里面

       // 方案一
        // 报错解决方法一
        axios.get('http://localhost:9090/student') // url 请求后台的地址
            /*
            * .then(function (response) 这样写前端会报错
            * 报错信息:TypeError: Cannot set properties of undefined (setting 'tableData')at eval (Student.vue?401d:59:1)
            * 这样写是匿名函数,无法取到tableData的值,所以tableData的值为undefined,不能给undefined的变量赋值
            * 解决办法:1.改为箭头函数 2.将this重新赋值给新的变量
            */
            // .then(function (response) { //成功回调方法(访问后台成功,后台有数据返回,则进入该方法)
            .then(response=> { //成功回调方法(访问后台成功,后台有数据返回,则进入该方法)
                console.log(response);
                console.log(response.data)
                this.tableData = response.data;
            })
            .catch(function (error) {//失败回调方法(访问后台失败,返回失败的信息,则进入该方法)
                console.log(error);
            });
    
      // 方案二
            //报错解决办法二
            var th = this;
            axios.get('http://localhost:9090/student') // url 请求后台的地址
                .then(function (response) { //成功回调方法(访问后台成功,后台有数据返回,则进入该方法)
                    console.log(response);
                    console.log(response.data)
                    th.tableData = response.data;
                })
                .catch(function (error) {//失败回调方法(访问后台失败,返回失败的信息,则进入该方法)
                    console.log(error);
                });
    

    方案一和方案二是为了解决报错:TypeError: Cannot set properties of undefined (setting 'tableData')at eval (Student.vue?401d:59:1),详情请看我的另一篇博客(博客链接:https://huanghaoheng.blog.csdn.net/article/details/126956987

    方案三:在前端项目结构搭建util
    在这里插入图片描述
    HttpRequest.js文件
    供读者复制粘贴的代码

    import axios from 'axios';
    export function requestHttp(config) {
    
        const instance = axios.create({
            baseURL: 'http://localhost:9090',
            timeout: 1000,
            headers: {'token': 'foobar'}
        });
    
        // 拼接 请求的信息 /student
       return instance(config)
    }
    

    修改Student.vue代码 在script中导入requestHttp

    import {requestHttp} from "@/util/HttpRequest";
    
     //方案三
                const config = {
                    url:"/student",
                    method:'get'
                }
               requestHttp(config) // url 请求后台的地址
                    .then(response=> { //成功回调方法(访问后台成功,后台有数据返回,则进入该方法)
                        console.log(response);
                        console.log(response.data)
                        this.tableData = response.data;
                    })
                    .catch(function (error) {//失败回调方法(访问后台失败,返回失败的信息,则进入该方法)
                        console.log(error);
                    });
    

    方案四 利用axios的拦截器
    HttpRequest.js

    import axios from 'axios';
    export function requestHttp(config) {
    
        const instance = axios.create({
            baseURL: 'http://localhost:9090',
            timeout: 1000,
            headers: {'token': 'foobar'}
        });
    
        // 添加请求拦截器
        instance.interceptors.request.use(function (config) {
            // 在发送请求之前做些什么
            return config;
        }, function (error) {
            // 对请求错误做些什么
            return Promise.reject(error);
        });
    
        // 添加响应拦截器
        instance.interceptors.response.use(function (response) {
            // 对响应数据做点什么
            if(response.status==200){
                return response.data;
            }
            return null;
        }, function (error) {
            // 对响应错误做点什么
            return Promise.reject(error);
        });
    
        // 拼接 请求的信息 /student
       return instance(config)
    }
    

    Student.vue
    script 导入

      import {requestHttp} from "@/util/HttpRequest";
    

    created()方法里面

     // 方案四
                 const config = {
                     url:"/student",
                     method:'get'
                 }
                requestHttp(config) // url 请求后台的地址
                     .then(response=> { //成功回调方法(访问后台成功,后台有数据返回,则进入该方法)
                         console.log(response);
                         console.log(response.data)
                         // 以下代码封装到响应拦截器中
                         // if(response.status==200){
                         //     this.tableData = response.data;
                         // }
                            this.tableData = response;
                     })
                     .catch(function (error) {//失败回调方法(访问后台失败,返回失败的信息,则进入该方法)
                         console.log(error);
                     });
    

    方案五:util中封装学生请求增删改查
    在这里插入图片描述
    StudentCRUD.js文件

    // 封装查询方法,暴露查询方法
    import {requestHttp} from "@/util/HttpRequest";
    
    export function selectStudentList() {
        const config = {
            url:"/student",
            method:'get'
        }
        return  requestHttp(config) // url 请求后台的地址
    }
    

    在Student,vue里面

     import {selectStudentList} from "@/util/StudentCRUD"
    
    //方案五
        selectStudentList()
            .then(response=> { //成功回调方法(访问后台成功,后台有数据返回,则进入该方法)
                console.log(response);
                console.log(response.data)
                // 以下代码封装到响应拦截器中
                // if(response.status==200){
                //     this.tableData = response.data;
                // }
                this.tableData = response;
            })
            .catch(function (error) {//失败回调方法(访问后台失败,返回失败的信息,则进入该方法)
                console.log(error);
            });
    

    方案六:
    util中封装学生请求增删改查
    在这里插入图片描述
    StudentCRUD.js文件

    // 封装查询方法,暴露查询方法
    import {requestHttp} from "@/util/HttpRequest";
    
    export function selectStudentList() {
        const config = {
            url:"/student",
            method:'get'
        }
        return  requestHttp(config) // url 请求后台的地址
    }
    

    在Student,vue里面

     import {selectStudentList} from "@/util/StudentCRUD"
    

    created()里面

    // 方案六
                this.showStudentList();
    

    methods里面

     methods:{
                //自定义查询方法
                showStudentList(){
                    selectStudentList()
                        .then(response=> { //成功回调方法(访问后台成功,后台有数据返回,则进入该方法)
                            console.log(response);
                            console.log(response.data)
                            // 以下代码封装到响应拦截器中
                            // if(response.status==200){
                            //     this.tableData = response.data;
                            // }
                            this.tableData = response;
                        })
                        .catch(function (error) {//失败回调方法(访问后台失败,返回失败的信息,则进入该方法)
                            console.log(error);
                        });
                }
            }
    
    看后端到步骤9项目目录结构创建*

    此时,后端 应该做到 步骤9StudentServlet.java文件
    此时npm installnpm run serve运行前段程序,同时后段运行tomcat服务器,再浏览中访问localhost:8080,点击Student路由,数据已经变成了数据库中的数据。展示效果如下:
    在这里插入图片描述

    7.新增学生信息

    Student.vue里面
    template标签里面
    新增学生信息按钮

     <!-- 新增学生信息对话框  按钮部分 -->
        <el-button type="primary"  @click="dialogVisible = true">新增学生信息</el-button>
    

    新增学生信息对话框

    <!-- 新增学生信息对话框  对话框部分 -->
    <!--center是否让 Dialog 的 header 和 footer 部分居中排列-->
    <!--destroy-on-close 关闭 Dialog 时,销毁其中的元素-->
    <el-dialog
            v-model="dialogVisible"
            :title="title"
            center
            width="60%"
            destroy-on-close>
        <!-- 新增学生信息对话框  表单部分 -->
        <el-form :model="studentForm" label-width="120px">
            <el-form-item label="姓名" prop="name">
                <el-input v-model="studentForm.name" type="text"/>
            </el-form-item>
            <el-form-item label="年龄" prop="age">
                <el-input v-model="studentForm.age" type="text"/>
            </el-form-item>
            <el-form-item label="性别">
                <el-radio-group v-model="studentForm.gender">
                    <el-radio label="1"></el-radio>
                    <el-radio label="0"></el-radio>
                </el-radio-group>
            </el-form-item>
            <el-form-item label="更新时间" prop="createTime">
                <el-date-picker
                        v-model="studentForm.createTime"
                        type="date"
                        placeholder="请选择日期"
                />
            </el-form-item>
        </el-form>
    
        <!-- 新增学生信息对话框  底部按钮部分 -->
        <template #footer>
      <span class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="submitBtn">保存</el-button>
      </span>
        </template>
    
    </el-dialog>
    

    scripts里面

        import { ElMessage } from 'element-plus'
        import {insertStudent, selectStudentList} from "@/util/StudentCRUD";
    

    data里面

      export default {
            data() {
                return {
                    tableData:[],
    
                    dialogVisible:false,
                    //学生信息对话框
                    studentForm:{
                        id:undefined,
                        name:undefined,
                        age:undefined,
                        gender:"0",
                        createTime:undefined
                    },
                    //新增学生信息对话框 标题
                    title:"学生信息添加"
    
                }
            },
    

    methods里面

      methods:{
                submitBtn(){//保存事件(新增,修改)
                    if(this.studentForm.id){
                        // 修改
                    }else {
                        // 新增
                        //JSON.stringify(js对象):把js对象转换成JSON格式的字符串
                        // alert(1);
                        // alert(JSON.stringify(this.studentForm));
    
                        //Qs.stringify()封装到HttpRequest里面
                        // insertStudent(Qs.stringify(this.studentForm))
                        insertStudent(this.studentForm)
                            .then(resp=>{
                                console.log(resp);
                                if(resp.success){
                                    //保存成功,刷新列表
                                    this.showStudentList();
                                    // dialog消失
                                    this.dialogVisible = false;
                                }else{
                                    ElMessage.error(resp.tip);
                                }
    
                            })
                            .catch(resp=>{
                                ElMessage.error("保存失败");
                            });
                    }
                },
    

    StudentCRUD.js里面新增如下代码

    // 封装新增方法,暴露新增方法
    export function insertStudent(student) {
        const config = {
            url:"/student?cmd=insert",
            method:'post',
            data:student
        }
        return  requestHttp(config) // url 请求后台的地址
    }
    

    修改HttpRquest.js
    导入Qs
    将前段发送的数据转成JSON

    import axios from 'axios';
    import Qs from 'qs'
    export function requestHttp(config) {
    
        const instance = axios.create({
            baseURL: 'http://localhost:9090',
            timeout: 1000,
            headers: {'token': 'foobar'},
    
      		// 将前段发送的数据转成JSON
            transformRequest: [function (data) {
                return Qs.stringify(data);
            }]
        });
    
        // 添加请求拦截器
        instance.interceptors.request.use(function (config) {
            // 在发送请求之前做些什么
            return config;
        }, function (error) {
            // 对请求错误做些什么
            return Promise.reject(error);
        });
    
        // 添加响应拦截器
        instance.interceptors.response.use(function (response) {
            // 对响应数据做点什么
            if(response.status==200){
                return response.data;
            }
            return null;
        }, function (error) {
            // 对响应错误做点什么
            return Promise.reject(error);
        });
    
        // 拼接 请求的信息 /student
       return instance(config)
    }
    

    新增按钮重置数据

       <!-- 新增学生信息对话框  按钮部分 -->
        <el-button type="primary"  @click="insertClick">新增学生信息</el-button>
    
      insertClick() {//新增弹框,重置数据
                    this.studentForm = {
                        id: undefined,
                        name: undefined,
                        age: undefined,
                        gender: 0,
                        createTime: undefined
                    },
                        this.dialogVisible = true;
                    this.title="学生信息添加";
                },
    
    8. 更新学生信息

    数据的回显
    Student.vue

      <template #default="scope">
                    <el-button link type="primary" size="small" @click="editById(scope.row)">编辑</el-button>
                    <el-button link type="primary" size="small">删除</el-button>
                </template>
    

    Student.vue methods里面

    editById(student) {//编辑弹框,回显数据
                    // alert(student);
                    // alert(JSON.stringify(student))
                    this.studentForm = {
                        id: student.id,
                        name: student.name,
                        age: student.age,
                        gender: student.gender,
                        createTime: student.createTime
                    },
                        this.dialogVisible = true;
                    this.title="学生信息修改";
                },
    

    StudentCRUD.js

    // 封装修改方法,暴露修改方法
    export function updateStudent(student) {
        const config = {
            url:"/student?cmd=update",
            method:'post',
            data:student
        }
        return  requestHttp(config) // url 请求后台的地址
    }
    

    在Student.vue

    import {insertStudent, selectStudentList,updateStudent} from "@/util/StudentCRUD";
    
      submitBtn() {//保存事件(新增,修改)
    
    
                    if (this.studentForm.id) {
                        // 修改
                        updateStudent(this.studentForm)
                            .then(resp => {
                                console.log(resp);
                                if (resp.success) {
                                    // 保存成功,刷新列表
                                    this.showStudentList();
                                    // dialog消失
                                    this.dialogVisible = false;
                                } else {
                                    ElMessage.error(resp.tip)
                                }
                            })
                            .catch(resp => {
                                ElMessage.error('保存失败')
                            });
    
    9.删除学生信息

    导入

       import { ElMessage, ElMessageBox } from 'element-plus'
       
    

    按钮

     <template #default="scope">
                    <el-button link type="primary" size="small" @click="editById(scope.row)">编辑</el-button>
                    <el-button link type="primary" size="small" @click="deleteById(scope.row)">删除</el-button>
                </template>
    
     methods: {
                deleteById(row){//删除 事件
                    ElMessageBox.confirm(
                        '您确定不要我了吗?',
                        'Warning',
                        {
                            confirmButtonText: '确定',
                            cancelButtonText: '取消',
                            type: 'warning',
                        }
                    )
                        .then(() => {
                            // 点击确定按钮
    
                            deleteById(row.id)
                                .then(resp=>{
                                    if(resp.success){
                                        // 刷新列表
                                        this.showStudentList();
                                    }else{
                                        ElMessage.info(resp.tip);
                                    }
                                })
                        })
    
                },
    

    StudentCRUD.js

    // 封装删除方法,暴露删除方法
    export function deleteById(id) {
        const config = {
            url:"/student?cmd=delete",
            method:'get',
            params:{
                "id":id
            }
        }
        return  requestHttp(config) // url 请求后台的地址
    }
    

    Student.vue

    import {insertStudent, selectStudentList, updateStudent,deleteById} from "@/util/StudentCRUD";
    

    二、后端

    1.建数据库、建表、导入项目数据

    因为是学生管理系统,所以笔者建的数据库名为student-mannage,表名为student,建议和笔者保持一致
    在这里插入图片描述
    供读者复制粘贴的代码
    数据库脚本

    /*
     Navicat Premium Data Transfer
    
     Source Server         : mysql57
     Source Server Type    : MySQL
     Source Server Version : 50738
     Source Host           : localhost:13306
     Source Schema         : student-manage
    
     Target Server Type    : MySQL
     Target Server Version : 50738
     File Encoding         : 65001
    
     Date: 23/09/2022 20:17:13
    */
    
    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for student
    -- ----------------------------
    DROP TABLE IF EXISTS `student`;
    CREATE TABLE `student`  (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `name` varchar(12) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
      `age` int(10) UNSIGNED NULL DEFAULT NULL,
      `gender` bit(1) NULL DEFAULT NULL,
      `create_time` date NULL DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE,
      INDEX `index_name`(`name`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
    
    -- ----------------------------
    -- Records of student
    -- ----------------------------
    INSERT INTO `student` VALUES (1, '张三丰', 23, b'1', '2022-03-01');
    INSERT INTO `student` VALUES (2, '李四民', 11, b'0', '2022-03-30');
    INSERT INTO `student` VALUES (3, '结衣', 12, b'1', '2022-08-08');
    INSERT INTO `student` VALUES (4, 'Lisa', 26, b'1', '2022-03-30');
    INSERT INTO `student` VALUES (5, 'tony', 32, b'1', '2022-08-07');
    INSERT INTO `student` VALUES (6, '露露', 2, b'1', '2022-08-07');
    INSERT INTO `student` VALUES (7, '丽丽', 13, b'1', '2022-08-12');
    INSERT INTO `student` VALUES (8, '花花', 14, b'1', '2022-08-12');
    INSERT INTO `student` VALUES (9, '猫咪', 15, b'1', '2022-08-12');
    INSERT INTO `student` VALUES (10, '如花', 17, b'1', '2022-08-12');
    INSERT INTO `student` VALUES (12, 'hhh', 23, b'1', '2022-09-17');
    
    SET FOREIGN_KEY_CHECKS = 1;
    

    2.在IDEA中搭建JavaWeb项目

    步骤可参考我的另一篇博客《IDEA2020创建JavaWeb项目并配置tomcat》
    博客链接: https://huanghaoheng.blog.csdn.net/article/details/126632499

    3.Tomcat配置

    在这里插入图片描述

    在这里插入图片描述

    4.导入jar包

    jar包下载地址如下:
    https://download.csdn.net/download/weixin_46411355/86720742

    5.项目目录结构搭建

    在这里插入图片描述

    6.Druid数据库连接池工具类的撰写

    util包下MyDruidUtil.java文件
    供读者复制粘贴的代码

    package com.bjpowernode.util;
    
    import com.alibaba.druid.pool.DruidDataSourceFactory;
    
    import javax.sql.DataSource;
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.Properties;
    
    public class MyDruidUtil {
    
        private MyDruidUtil(){
    
        }
    
        private static DataSource dataSource;
    
        static {
            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            try {
                properties.load(inputStream);
                dataSource = DruidDataSourceFactory.createDataSource(properties);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static Connection getConnection() {
            try {
                return dataSource.getConnection();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            return null;
        }
    
        public static void releaseSource(ResultSet resultSet, PreparedStatement preparedStatement, Connection connection) {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
    
            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
    
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
    
        public static void releaseSource(PreparedStatement preparedStatement, Connection connection) {
            releaseSource(null,preparedStatement,connection);
        }
    }
    

    7.module层 Student类的创建

    domain或者pojo包下Student.java文件
    供读者复制粘贴的代码

    package com.bjpowernode.domain;
    
    import java.util.Date;
    import java.util.Objects;
    
    public class Student {
        private Long id;
        private String name;
        private Integer age;
        private int gender;
        private Date createTime;
    
        public Student() {
        }
    
        public Student(Long id, String name, Integer age, int gender, Date createTime) {
            this.id = id;
            this.name = name;
            this.age = age;
            this.gender = gender;
            this.createTime = createTime;
        }
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public int getGender() {
            return gender;
        }
    
        public void setGender(int gender) {
            this.gender = gender;
        }
    
        public Date getCreateTime() {
            return createTime;
        }
    
        public void setCreateTime(Date createTime) {
            this.createTime = createTime;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    ", gender=" + gender +
                    ", createTime=" + createTime +
                    '}';
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Student student = (Student) o;
            return gender == student.gender &&
                    Objects.equals(id, student.id) &&
                    Objects.equals(name, student.name) &&
                    Objects.equals(age, student.age) &&
                    Objects.equals(createTime, student.createTime);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(id, name, age, gender, createTime);
        }
    }
    

    8.dao层(StudentDAO)及其实现类(StudentDAOImpl)

    dao包下的StudentDAO文件
    供读者复制粘贴的代码

    package com.bjpowernode.dao;
    
    import com.bjpowernode.domain.Student;
    import java.util.*;
    
    public interface StudentDAO {
        int insert(Student student);
    
        int deleteById(Long id);
    
        int update(Student student);
    
        List<Student> listAll();
    
        Student selectById(Long id);
    }
    

    dao包下的impl包下的StudentDAOImpl文件(目前实现了listAll查询全部学生列表的方法)
    供读者复制粘贴的代码

    package com.bjpowernode.dao.impl;
    
    
    import com.bjpowernode.dao.StudentDAO;
    import com.bjpowernode.domain.Student;
    import com.bjpowernode.util.MyDruidUtil;
    
    import java.sql.Connection;
    import java.sql.Date;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.util.ArrayList;
    import java.util.List;
    
    public class StudentDAOImpl implements StudentDAO {
    
        @Override
        public int insert(Student student) {
         
                return 0;
      
        }
    
    
        @Override
        public int deleteById(Long id) {
            return 0;
        }
    
        @Override
        public int update(Student student) {
            return 0;
        }
    
        @Override
        public List<Student> listAll() {
            List<Student> studentList = new ArrayList<>();
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
            try {
                connection = MyDruidUtil.getConnection();
                String sql = "select * from student";
                preparedStatement = connection.prepareStatement(sql);
                resultSet = preparedStatement.executeQuery();
                while (resultSet.next()) {
                    Student student = new Student();
                    student.setId(resultSet.getLong("id"));
                    student.setAge(resultSet.getInt("age"));
                    student.setGender(resultSet.getInt("gender"));
                    student.setCreateTime(resultSet.getDate("create_time"));
                    student.setName(resultSet.getString("name"));
                    studentList.add(student);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                MyDruidUtil.releaseSource(resultSet, preparedStatement, connection);
            }
            return studentList;
        }
    
        @Override
        public Student selectById(Long id) {
            return null;
        }
    }
    

    9.JSONResult类

    package com.bjpowernode.result;
    
    import com.alibaba.fastjson.JSONObject;
    
    public class JSONResult {
        private boolean success = true;
        private String tip;
    
        // 操作失败 调用这个 方法
        public JSONResult mark(String tip){
            this.tip = tip;
            this.success = false;
            return this;
        }
    
        public boolean isSuccess() {
            return success;
        }
    
    
    
        public String getTip() {
            return tip;
        }
    
    
    }
    

    11.StudentServlet.java文件

    servlet包下StudentServlet.java文件
    供读者复制粘贴的代码

    package com.bjpowernode.servlet;
    
    import com.alibaba.fastjson.JSON;
    import com.bjpowernode.dao.StudentDAO;
    
    import com.bjpowernode.dao.impl.StudentDAOImpl;
    import com.bjpowernode.domain.Student;
    import com.bjpowernode.result.JSONResult;
    
    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.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.List;
    
    @WebServlet("/student")
    public class StudentServlet extends HttpServlet {
    
        private StudentDAO studentDAO = new StudentDAOImpl();
    
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            // 处理post请求乱码
            req.setCharacterEncoding("utf-8");
            //告知前端(vue),返回给vue的数据格式是json,内容使用utf-8编码解析
            resp.setContentType("application/json;charset=utf-8");
    
            // 解决跨域的问题
            //        resp.addHeader("Access-Control-Allow-Origin", "*");//任意协议、IP、端口都接收
            resp.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");//只允许localhost:8080访问我
            resp.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
    //        resp.addHeader("Access-Control-Allow-Headers", "Content-Type");
            resp.addHeader("Access-Control-Allow-Headers", "*");//所有的格式
            resp.addHeader("Access-Control-Max-Age", "3600");//访问的超时时间多少毫秒
    
            String method = req.getMethod();
            if(method.equals("OPTIONS")){
                PrintWriter writer = resp.getWriter();
                writer.write("允许访问");
                return;
            }
    
            // 因为所有的请求都会进入service方法中,
            // 那么crud地址不同,如何在一个Servlet中进行区分
            // 解决方案:在地址栏后面拼接参数。然后在后台根据参数区分操作
    
            //接收参数cmd,为了区分是什么请求
            String cmd = req.getParameter("cmd");
    
            //使用一个三元运算符把cmd为null的情况 改成字符串
            cmd = cmd == null ? "" : cmd;
            switch (cmd) {
                case "insert":
                    insertMethod(req,resp);
                    break;
                default:
                    selectStudentList(req,resp);
            }
    
    
    
        }
    
        private void selectStudentList(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            List<Student> studentList = studentDAO.listAll();
            studentList.forEach(System.out::println);
    
            //把数据转成JSON格式的字符串
            String studentListJsonString = JSON.toJSONString(studentList);
    
            //通过响应对象,给到vue
            PrintWriter writer = resp.getWriter();
            writer.write(studentListJsonString);
            writer.flush();
        }
    

    12. CORSFilter类

    解决前后段跨域问题 将 StudentServlet中的这部分代码封装到CORSFilter类中

    package com.bjpowernode.filter;
    import java.io.IOException;
    
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @WebFilter("/*")
    public class CORSFilter implements Filter {
    
    
    
        @Override
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain)
                throws IOException, ServletException {
            System.out.println("come in ");
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;
            response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
            response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
            response.addHeader("Access-Control-Allow-Headers", "*");
            response.addHeader("Access-Control-Max-Age", "1800");//30 min
            filterChain.doFilter(request, response);
        }
    
    
    }
    

    13.新增学生

    StudentDAOImpl类中

       @Override
        public int insert(Student student) {
            Connection connection = null;
            PreparedStatement preparedStatement = null;
    
            try {
                connection = MyDruidUtil.getConnection();
                // 获取预编译语句对象
                String sql = "insert into student(name,age,gender,create_time) values(?,?,?,?)";
                preparedStatement = connection.prepareStatement(sql);
                // 设置参数
                preparedStatement.setString(1,student.getName());
                preparedStatement.setInt(2,student.getAge());
                preparedStatement.setInt(3,student.getGender());
                preparedStatement.setDate(4,new Date(student.getCreateTime().getTime()));
                // 执行sql
                return preparedStatement.executeUpdate();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                MyDruidUtil.releaseSource(preparedStatement,connection);
            }
            return 0;
        }
    

    StudentServlet文件中

       private void insertMethod(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            // 接收参数
            String name = req.getParameter("name");
            String age = req.getParameter("age");
            String gender = req.getParameter("gender");
            String createTime = req.getParameter("createTime");
    
            // 封装对象
            Student student = new Student();
            student.setName(name);
            if(age!=null&&!age.equals("")){
                student.setAge(Integer.valueOf(age));
            }
            if(gender!=null&&!gender.equals("")){
                student.setGender(Integer.valueOf(gender));
            }
            if(createTime!=null&&!createTime.equals("")){
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                try {
                    Date date = simpleDateFormat.parse(createTime);
                    student.setCreateTime(date);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
    
            }
            // 调用dao方法,保存数据
            int result = studentDAO.insert(student);
            JSONResult jsonResult = new JSONResult();
            PrintWriter writer = resp.getWriter();
            if(result>0){
                // 保存成功
                String jsonString = JSON.toJSONString(jsonResult);
                writer.write(jsonString);
            }else{
                // 保存失败
                String jsonString = JSON.toJSONString(jsonResult.mark("保存失败,请稍后重试"));
                writer.write(jsonString);
            }
    
    }
    

    14.修改学生信息

    StudentServlet文件中

      cmd = cmd == null ? "" : cmd;
            switch (cmd) {
                case "insert":
                    insertMethod(req,resp);
                    break;
                case "update":
                    updateMethod(req,resp);
                    break;
                default:
                    selectStudentList(req,resp);
            }
    
     private void updateMethod(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            //接收参数
            String id = req.getParameter("id");
            String name = req.getParameter("name");
            String age = req.getParameter("age");
            String gender = req.getParameter("gender");
            String createTime = req.getParameter("createTime");
            //封装对象
            Student student = new Student();
            student.setName(name);
            if(id!=null&&!id.equals("")){
                student.setId(Long.valueOf(id));
            }
            if (age != null && !age.equals("")) {
                student.setAge(Integer.valueOf(age));
            }
            if (gender != null && !gender.equals("")) {
                student.setGender(Integer.valueOf(gender));
            }
    
    
            if (createTime != null && !createTime.equals("")) {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                try {
                    Date date = simpleDateFormat.parse(createTime);
                    student.setCreateTime(date);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
    
            }
            // 调用dao 方法 保存数据
            int result = studentDAO.update(student);
            JSONResult jsonResult = new JSONResult();
            PrintWriter writer = resp.getWriter();
            if (result > 0) {
                //保存成功
                String jsonString = JSON.toJSONString(jsonResult);
                writer.write(jsonString);
            } else {
                //保存失败
                String jsonString = JSON.toJSONString(jsonResult.mark("保存失败,请稍后重试"));
                writer.write(jsonString);
            }
    
        }
    

    StudentDAOImpl文件

    @Override
        public int update(Student student) {
            Connection connection = null;
            PreparedStatement preparedStatement = null;
    
            try {
                connection = MyDruidUtil.getConnection();
                // 获取预编译语句对象
                String sql = "update student set name = ?,age=?,gender=?,create_time=? where id = ?";
                preparedStatement = connection.prepareStatement(sql);
                // 设置参数
                preparedStatement.setString(1,student.getName());
                preparedStatement.setInt(2,student.getAge());
                preparedStatement.setInt(3,student.getGender());
                preparedStatement.setDate(4,new Date(student.getCreateTime().getTime()));
                preparedStatement.setLong(5,student.getId());
                // 执行sql
                return preparedStatement.executeUpdate();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                MyDruidUtil.releaseSource(preparedStatement,connection);
            }
            return 0;
        }
    

    15.删除学生信息

    StudentServlet

     case "delete":
                    deleteMethod(req,resp);
                    break;
    
     private void deleteMethod(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            String id = req.getParameter("id");
            System.out.println("id = " + id);
            if (id!=null&&!id.equals("")){
                int result = studentDAO.deleteById(Long.valueOf(id));
                JSONResult jsonResult = new JSONResult();
                PrintWriter writer = resp.getWriter();
                if (result > 0) {
                    //删除成功
                    String jsonString = JSON.toJSONString(jsonResult);
                    writer.write(jsonString);
                } else {
                    //删除失败
                    String jsonString = JSON.toJSONString(jsonResult.mark("删除失败,请稍后重试"));
                    writer.write(jsonString);
                }
            }
    

    StudentDAOImpl

     @Override
        public int deleteById(Long id) {
            Connection connection = null;
            PreparedStatement preparedStatement = null;
    
            try {
                connection = MyDruidUtil.getConnection();
                // 获取预编译语句对象
                String sql = "delete from student where id = ?";
                preparedStatement = connection.prepareStatement(sql);
                preparedStatement.setLong(1,id);
                // 执行sql
                return preparedStatement.executeUpdate();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                MyDruidUtil.releaseSource(preparedStatement,connection);
            }
            return 0;
        }
    
  • 相关阅读:
    喂饭级AI神器!免代码一键绘制图表,文本数据秒变惊艳视觉盛宴!
    PaddleOCR-EAST
    【51单片机】利用【时间延迟】的原理规避【按键抖动问题】
    Linux高性能服务器编程 学习笔记 第七章 Linux服务器程序规范
    9.30作业
    思腾云计算
    多人协作代码管理工具 gitlab 实战演练
    前端程序员应该了解的Typescript
    【微机原理|课程报告】计算器课设报告
    记录窗体关闭位置(从窗体上次关闭的位置启动窗体)
  • 原文地址:https://blog.csdn.net/weixin_46411355/article/details/126903197