• javaee三层架构案例--简单学生管理系统


    背景

    学了jdbc、jsp等需要串起来,不然会忘记

    项目环境

    win10
    jdk11
    mysql8.0.13

    jar包

    c3p0-0.9.5.2
    commons-dbutils-1.7
    jstl
    mchange-commons-java-0.2.11
    mysql-connector-java-8.0.14
    standard

    项目地址

    还不会用github,所以只能这样咯

    链接:https://pan.baidu.com/s/1JwSag2RIEBVhGZVAETNqlQ
    提取码:o0x3
    复制这段内容后打开百度网盘手机App,操作更方便哦

    准备数据库

    /*创建一个存放学生信息的表格*/
    
    /*创建数据库stus*/
    CREATE DATABASE stus; 
    /*使用stus*/
    USE stus;
    /*创建学生表stu*/
    CREATE TABLE stu(
      sid INT PRIMARY KEY AUTO_INCREMENT,
      sname VARCHAR(20),
      gender VARCHAR(5),
      phone VARCHAR(20),
      birthday DATE,
      hobby VARCHAR(50),
      info VARCHAR(200)
    );
    

    做一个主页

    通过IDEA在web目录下创建一个index.jsp作为主页
    页面先只有一个超链接叫做 显示所有学生列表
    还没写链接到哪个Servlet,用 # 先代替下,等创建好了再写回来

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
       <title>首页</title>
    </head>
    <body>
    <h3><a href="/studentList">显示所有学生列表</a></h3>
    </body>
    </html>
    

    创建一个Servlet

    index.jsp标记1出用的Servlet,创一个Servlet的包,创一个StudentListServlet类,用doGet方法(转发需要用doGet方法,且用doPost没有这个需求)

    Servlet接受用户点击,去通知service实现业务逻辑

    //这个是用反射,写在类上一行,也可以在web.xml中配置Servlet
    @WebServlet(name = "StudentListServlet",urlPatterns = {"/StudentListServlet"})
    
    //写在doGet方法然后在doPost方法中互调....
    //因为之后转发只能用doGet方法,有点麻烦
    
    //面向接口编程
    //StudentService:接口 StudentServiceImpl:接口实现类
    StudentService service = new StudentServiceImpl();
    //调用实现类的findAll方法,把结果放在一个list表中,泛型为Student对象
    List<Student> list = service.findAll();
    
    

    创建Student类

    上文中缺少Student类,这是一个JavaBean,封装用。

    !!!JavaBean一定要有一个空参!!!

    !!!JavaBean是用空参来反射得到实例的!!!

    创建domian包,里面创建Student类,包含和数据库名字、类型对应的成员变量

    //数据类型为Date的导util包,sql包中的Date也是继承该util包中的  
    import java.util.Date;
    	private int sid;
        private String sname;
        private String gender;
        private String phone;
        private Date birthday;
        private String hobby;
        private String info;
    //生成getXxx和setXxx方法
    //生成toString方法
    

    创建一个Service接口和Service的实现类

    上面没有Service接口,创建一个service包,下面创建StudentService接口

    这里是为了实现学生业务逻辑的处理规范

    目前只有一个查找所有学生信息的业务

    public interface StudentService {
    	//这里的throws SQLException是在最后面dao层发现需要抛,一步一步返回来的,当然IDEA中一键生成
        List<Student> findAll() throws SQLException;
    }
    

    创建接口的实现类,在service包下创建一个impl包,在impl包内创建StudentServiceImpl实现类

    实现学生业务,findAll方法是去数据库中查询,因此要调用查询数据库的方法

    public class StudentServiceImpl implements StudentService {
        @Override
        public List<Student> findAll() throws SQLException {
            //StudentDao:接口 StudentDaoImpl:实现类
            StudentDao dao = new StudentDaoImpl();
            return dao.findAll();
        }
    }
    

    创建dao层中接口和实现类

    创建一个dao包,创建StudentDao接口,在dao包中创建一个impl包,里面创建一个StudentDaoimpl实现类

    public interface StudentDao {
        List<Student> findAll() throws SQLException;
    }
    

    StudentDaoImpl实现findAll方法,通过C3P0,自己的工具类JDBCUtil调用

    通过数据库代码查询,结果返回到BeanListHandler<>(Student.class)中

    public class StudentDaoImpl implements StudentDao {
        @Override
        public List<Student> findAll() throws SQLException {
            QueryRunner runner = new QueryRunner(JDBCUtil02.getDataSource());
            String sql = "SELECT * FROM stu";
            return runner.query(sql, new BeanListHandler<>(Student.class));
        }
    }
    

    把查询出的结果发到list.jsp中

    在StudentListServlet类的doGet方法中,要把结果存到request域中

    //名字就叫list,值也是list
    request.setAttribute("list",list);
    

    再把结果转发到list.jsp中,不需要改变页面地址

    request.getRequestDispatcher("list.jsp").forward(request, response);
    

    目前先做红框内的东西,分析一下,就是2行8列,一行是标题,一行是内容(靠循环出来的结果)

    要用el表达式,导包jstl.jar和standard.jar
    导jstl标签库

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%--2行8列展示结果--%>
    <table border="1px" width="600px">
        <tr>
            <td>编号</td>
            <td>姓名</td>
            <td>性别</td>
            <td>电话</td>
            <td>生日</td>
            <td>爱好</td>
            <td>简介</td>
            <td>操作</td>
        </tr>
        <c:forEach items="${list }" var="stu">
        <tr>
            <td>${stu.sid }</td>
            <td>${stu.sname }</td>
            <td>${stu.gender }</td>
            <td>${stu.phone }</td>
            <td>${stu.birthday }</td>
            <td>${stu.hobby }</td>
            <td>${stu.info }</td>
            <td>!~~~超链接还没写,等下补完<a href="#">更新</a><a href="#">删除</a></td>
        </tr>
        </c:forEach>
    

    第一步小结

    用图片来表示以下上面的流程


    继续完善list.jsp

    做一个添加功能,其他先不管

    所以让我们继续补充一个超链接

    提交到add.jsp中吧

        <tr>
            <td colspan="8"><a href="add.jsp">添加</a></td>
        </tr>
    

    没有add.jsp,我们在web文件夹下创建一个,大概长这个样子


    信息很多,我们用post方法提交,交到一个addServlet让他处理

    <h3>添加学生页面</h3>
    <form action="${pageContext.request.contextPath}/addServlet" method="post">
        <table border="1px" width="600px">
            <tr>
                <td>姓名</td>
                <td><input type="text" name="sname"/></td>
            </tr>
            <tr>
                <td>性别</td>
                <td>
                    <input type="radio" name="gender" value="男" checked/>男
                    <input type="radio" name="gender" value="女"/>女
                </td>
            </tr>
            <tr>
                <td>电话</td>
                <td><input type="text" name="phone"/></td>
            </tr>
            <tr>
                <td>生日</td>
                <td><input type="text" name="birthday"/></td>
            </tr>
            <tr>
                <td>爱好</td>
                <td>
                    <input type="checkbox" name="hobby" value="游泳"/>游泳
                    <input type="checkbox" name="hobby" value="篮球"/>篮球
                    <input type="checkbox" name="hobby" value="足球"/>足球
                    <input type="checkbox" name="hobby" value="看书"/>看书
                    <input type="checkbox" name="hobby" value="写字"/>写字
                </td>
            </tr>
            <tr>
                <td>简介</td>
                <td><textarea name="info" rows="3" cols="20"></textarea></td>
            </tr>
            <tr>
                <td colspan="2">
                    <input type="submit" value="添加"/>
                </td>
            </tr>
        </table>
    </form>
    

    addServlet要做什么呢

    1. 中文乱码问题解决
    2. 要获取客户端提交上来的数据并处理
    3. 把数据打包交给service进行业务处理
    4. 交给别人展示数据

    实现过程

    1. 中文乱码问题解决

      request.setCharacterEncoding("UTF-8");
      
    2. 获取客户端提交上来的数据

                  String sname = request.getParameter("sname");
                  String gender = request.getParameter("gender");
                  String phone = request.getParameter("phone");
                  String birthday = request.getParameter("birthday");
                  String hobby = request.getParameter("hobby");
                  String info = request.getParameter("info");
      

      并处理下,考虑到birthday是data类型,要转换下

      Date date = new SimpleDateFormat("yyyy-MM-dd").parse(birthday);
      

      这里要注意下,用getParemeter方法得到的参数永远只有一个,对于爱好需要传入很多个,因此考虑使用getParameterValues方法,返回一个String[ ]数组,用Arrays.toString方法,打印之后发现有多出[ ],用substring方法截取中间段

       String hobby = Arrays.toString(request.getParameterValues("hobby"));
       hobby = hobby.substring(1, hobby.length() - 1);
    
    1. 把数据打包

      就是弄个JavaBean对象封装一下,用一堆set方法有点麻烦,直接在Student类中增加一个带参的构造器(之前写了空参的好处就在此,不会忘记写)

      Student student = new Student(sname, gender, phone, date, hobby, info);
      

      交给service进行业务处理

      取名为insert方法吧,等会去service中生成需要的接口和对应的实现类

      StudentService service = new StudentServiceImpl();
      service.insert(student);
      
    2. 交给别人展示数据

      这里就是把结果返回给list.jsp中啦。如果直接转发到list.jsp,会有一个问题,request域中是空的,会没有元素。因此需要重新转发到对应的Servlet中

      目前看起来转发需要加 / ,对其路径的获取还不是很懂

      request.getRequestDispatcher("/StudentListServlet").forward(request,response);
      

    继续写全service

    1. 把StudentService补全,把其实现类补全

      接口就多一个insert方法

          /**
           * 需要添加到数据库的学生对象
           * @param student 封装
           * @throws SQLException 异常
           */
          void insert(Student student) throws SQLException;
      

      实现类

      业务没什么新的,就是在数据库里加东西,调用DAO层

          @Override
          public void insert(Student student) throws SQLException {
              StudentDao dao = new StudentDaoImpl();
              dao.insert(student);
          }
      

    该传到DAO层了

    1. 把DAO补全,把其实现类补全

      接口和前面service层的接口是一样的

          /**
           * 需要添加到数据库的学生对象
           * @param student 封装
           * @throws SQLException 异常
           */
          void insert(Student student) throws SQLException;
      

      实现类

      之前sql代码打错了,大家一定要在sql试过了再写进来,这样成功率高点

       @Override
          public void insert(Student student) throws SQLException {
              QueryRunner runner = new QueryRunner(JDBCUtil02.getDataSource());
      
              //INSERT INTO stu VALUES(NULL,'姓名','性别','电话','1999-1-1','爱好','备注');
              runner.update("INSERT INTO stu VALUES(null,?,?,?,?,?,?)",
                      student.getSname(),
                      student.getGender(),
                      student.getPhone(),
                      student.getBirthday(),
                      student.getHobby(),
                      student.getInfo()
              );
          }
      

    添加功能小结

    1. 做个jsp表单界面,注意name属性,这是之后获取参数用的

    2. 做个提交过去的Servlet

    3. Servlet收集数据,处理数据,封装数据,传递数据(service),展示数据(转发,可以发给Servlet)

    4. service处理业务逻辑,遇到对数据库处理的部分,调用dao层

    5. dao实现对数据库的处理



    制作更新相关的功能

    需求

    1. 点击更新能得到当前行的信息,跳到一个新的页面上
    2. 在表格上更改后点击按钮能更新数据库并在list页面上显示

    1.点击更新能得到当前行的列表资料

    这个页面和之前的添加页面差不多,稍微有点不同。我们直接复制为edit.jsp,稍作修改

    需要获取查询的内容,自然使用servlet来处理

    list.jsp需要改动的部分

    取名为EditServlet,传一个sid为参数,el表达式中的stu是之前jstl的for循环出来的,此时request域中还有。

    <a href="EditServlet?sid=${stu.sid}">更新</a>
    

    EditServlet需求分析

    1. 获取传来是sid
    2. 通知service去实现需要的业务逻辑
    3. 传参数到request域中
    4. 带着request域转发到edit.jsp

    EditServlet实现相关代码

    1. 获取传来是sid

      //转成int类型,比较方便
      int sid = Integer.parseInt(request.getParameter("sid"));
      
    2. 通知service去实现需要的业务逻辑

      //这里是要通过sid查到对应的人,之后要对后续流程做出相应的更改
      StudentService service = new StudentServiceImpl();
      Student student = service.findStudentById(sid);
      
    3. 传参数到request域中

      //以示区分,设为student(不过用stu也是一样的)
      request.setAttribute("student", student);
      
    4. 带着request域转发到edit.jsp

      request.getRequestDispatcher("edit.jsp").forward(request,response);
      

    对Service/DAO补上相关功能

    1. service

    StudentService接口,补一个findStudentById方法

    /**
     * 找到某条学生数据
     * @param sid 学生ID
     * @return  学生对象
     * @throws SQLException sql异常
     */
    Student findStudentById(int sid) throws SQLException;
    

    StudentServiceImpl实现类,补一个业务流程处理,涉及数据库的CRUD部分,调用DAO

    @Override
    public Student findStudentById(int sid) throws SQLException {
        StudentDao dao = new StudentDaoImpl();
        return dao.findStudentById(sid);
    }
    

    1. dao

    接口,就是做个抽象类,通过sid返回一个Student对象,因为之后要显示到界面还需要提取参数

    /**
     * 找到某条学生数据
     * @param sid 学生ID
     * @return  学生对象
     * @throws SQLException sql异常
     */
    Student findStudentById(int sid) throws SQLException;
    

    实现类,通过sql语句找到对应的数据,返回只有一条结果,用BeanHandler就好

    @Override
    public Student findStudentById(int sid) throws SQLException {
        QueryRunner runner = new QueryRunner(JDBCUtil02.getDataSource());
        String sql = "SELECT * FROM stu WHERE sid = ?";
        return runner.query(sql, new BeanHandler<>(Student.class), sid);
    }
    

    最终返回到edit.jsp中之后,要在相对应的地方获取对应的数据

    type="text" 用value="${对应的数据}",举例

    <input type="text" name="sname" value="${student.sname}"/>
    

    type="radio",需要用对应的结果选中的,参数是checked,需要用if来判断一下。这里引入jstl核心标签。如果传入的文字是男,则设置为checked。女同理。

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <input type="radio" name="gender" value="男" <c:if test="${student.gender == '男'}">checked</c:if>/>男
    <input type="radio" name="gender" value="女" <c:if test="${student.gender == '女'}">checked</c:if>/>女
    

    type="checkbox",需要用对应的结果选中的,参数也是checked。但是爱好很多,这里不是用if,而是用包含contains来选择。引入jstl的function库。其余类似。

    <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
    <input type="checkbox" name="hobby" value="游泳" <c:if test="${fn:contains(student, '游泳')}">checked</c:if>/>游泳
    

    textarea,需要在里面显示字的,直接在尖括号外面。

    <textarea name="info" rows="3" cols="20">${student.info}</textarea>
    

    到这里,第一步显示数据就完成了。

    2. 在表格上更改后点击按钮能更新数据库并在list页面上显示

    表单提交的地方要改一下,涉及到业务,还是用servlet

    servlet需求:获取edit.jsp的数据,封装成JavaBean,传到service,再展示结果。和addServlet差不多,直接复制修改。

    service、dao和上文都差不多,方法名用update吧,对数据库的操作中,因为没有传sid回来,因此就用其他的数据作为where条件

    daoImpl的代码

    @Override
    public void update(Student student) throws SQLException {
       QueryRunner runner = new QueryRunner(JDBCUtil02.getDataSource());
       String sql = "UPDATE stu SET sname=?,gender=?,phone=?,birthday=?,info=? WHERE sid=?";
       //注意这里的要多一个sid,那么到底能不能传过来sid呢?
       runner.update(sql,
               student.getSname(),
               student.getGender(),
               student.getPhone(),
               student.getBirthday(),
               student.getInfo(),
               student.getSid()
       );
    }
    

    让我们从点击更新按钮开始,回顾整个流程。

    1. list.jsp中点击更新===》"EditServlet?sid=${stu.sid}"

    这里是带着一个sid的

    1. EditServlet中调用service.findStudentById(sid),传到dao.findStudentById(sid),我们打印下这里返回的对象,发现返回的student对象是带有sid的。

    2. EditServlet转发到edit.jsp中,那么edit.jsp的request域中的student是带有sid的。

    3. edit.jsp点击提交到UpdateServlet。但是没有sid。因此问题出在edit.jsp中。

    4. edit.jsp发现没有调用出sid的代码,因此我们补充一个。

    <input type="hidden" name="sid" value="${student.sid}" />
    

    更新代码小结

    逻辑都差不多,一层调用一层,前面懂了这里自然懂。

    不过需要注意一些小问题。比如最后的sid,以及如何分析问题出在哪里的方法:按流程寻找法。


    最后分页查询功能

    这是界面效果

    三层架构的业务处理逻辑

    这个是我今天刚刚感受出来的

    service封装各种JavaBean,然后回到servlet中展示数据,最后在jsp里调用域中的数据

    制作过程

    我个人喜欢从jsp开始做起来,缺什么补什么。

    首先是一个入口,在index.jsp加入一行代码。StudentListPageServlet,再传一个参数currentPage=1

    <h3><a href="${pageContext.request.contextPath}/StudentListPageServlet?currentPage=1">分页显示学生列表</a></h3>
    

    1.servlet

    //1.获取数据 : 获取页码数
    int currentPage = Integer.parseInt(request.getParameter("currentPage"));
    
    //2.得到处理好的封装数据
    //这里创建一个新的JavaBean,因为一方面要保存查询出来的List,另一方面要保存当前页面、所有页面信息。但是JavaBean中要存放多少东西呢,不知道。做到后面,缺啥补啥。反正用原来的JavaBean不行就是了
    StudentService service = new StudentServiceImpl();
    PageBean<Student> studentByPage = service.findStudentByPage(currentPage);
    
    
    //3.显示数据 : 存到quest域中转发
    //因为现在我习惯流程来继续制作,所以第三步先不写了。
    

    2.StudentService和其实现类

    /**
    * 查询当前页的数据
    * @param currentPage 页码数
    * @return 查询出的学生列表
    * @throws SQLException SQL
    */
     PageBean<Student> findStudentByPage(int currentPage) throws SQLException;
    
    @Override
    public PageBean<Student> findStudentByPage(int currentPage) throws SQLException {
    	PageBean<Student> pageBean = new PageBean<>();
    	StudentDao dao = new StudentDaoImpl();
    	//第一步就是要得出list
    	List<Student> list = dao.findStudentByPage(currentPage);
    

    3.StudentDao及其实现类

    这是查询的分页list

    /**
     * 查询当前页的数据
     * @param currentPage 页码数
     * @return 查询出的学生列表
     * @throws SQLException SQL
     */
    List<Student> findStudentByPage(int currentPage)throws SQLException;
    
    @Override
    public List<Student> findStudentByPage(int currentPage) throws SQLException {
        QueryRunner runner = new QueryRunner(JDBCUtil02.getDataSource());
        String sql = "SELECT * FROM stu LIMIT ? OFFSET ?";
        //PAGE_SIZE是5,常数,第二个参数是偏移量。
        List<Student> query = runner.query(sql, new BeanListHandler<>(Student.class), PAGE_SIZE, (currentPage - 1) * PAGE_SIZE);
        return query;
    }
    

    补完servlet,制作pageList.jsp

    接着从dao层往回传,到了servlet处,补充完

    //3.显示数据 : 存到quest域中转发,名字为studentByPage,之后可以在jsp中取出对应的数据
    request.setAttribute("studentByPage",studentByPage);
    request.getRequestDispatcher("pageList.jsp").forward(request, response);
    

    制作JavaBean

    通过PageBean

    public class PageBean<T> {
        //目前只需要一个list
        private List<T> list;
    }
    

    制作pageList.jsp

    这个界面和查询的界面差不多,因此复制list.jsp,改名为pageList.jsp。

    因为上步servlet中是存到request域中的studentByPage里面,page中将表达式中的list改为studentByPage.list

     <c:forEach items="${studentByPage.list }" var="stu">
                <tr>
                    <td>${stu.sid }</td>
                    <td>${stu.sname }</td>
                    <td>${stu.gender }</td>
                    <td>${stu.phone }</td>
                    <td>${stu.birthday }</td>
                    <td>${stu.hobby }</td>
                    <td>${stu.info }</td>
                    <td><a href="EditServlet?sid=${stu.sid}">更新</a> <a href="#" onclick="doDelete(${stu.sid})">删除</a></td>
                </tr>
            </c:forEach>
    

    对比下jsp页面,lis分页已经好了,我们来制作最下面页码行。我们先做预处理,把需要的的东西先静态表示出来。下图是最后一行东西。

    这个中括号内的数据都是动态的,也是需要从request域中取出的数据。因此按上面的流程,request域是servlet传的JavaBean中。因此只要把相关数据存到JavaBean对象即可。因此在JavaBean中加入相关的成员变量,并在service层中加入对应处理。

    对service、dao等进行处理

    在service中进行相应的处理

    1. 当前页,是可以直接获得的,在方法传入的参数中

      pageBean.setCurrentPage(currentPage);
      
    2. 总页数,需要稍作处理。逻辑是,先获取所有条数count,然后用其除每页条数,如果除不尽就多算一页。获取count是对数据库操作,因此依次补上需要的代码。以下是关键代码:

      //dao层对数据库的操作
      @Override
      public int findCount() throws SQLException {
          QueryRunner runner = new QueryRunner(JDBCUtil02.getDataSource());
          String sql = "SELECT COUNT(*) FROM stu";
          //ScalarHandler<>()常用来存数字,如count值,平均值等,数据类型是long,需要一个强转
          Long query = runner.query(sql, new ScalarHandler<>());
          return Math.toIntExact(query);
      }
      
      //service中对页数的处理
      int count = dao.findCount();
      int countAllPage = count % StudentDaoImpl.PAGE_SIZE == 0 ? count / StudentDaoImpl.PAGE_SIZE : count % StudentDaoImpl.PAGE_SIZE + 1;
      //存入request域中
      pageBean.setCountAllPage(countAllPage);
      
    3. 每页显示的条数,就是存在DAO实例中的常数

      pageBean.setPageSize(StudentDaoImpl.PAGE_SIZE);
      
    4. 总记录,在总页数那里已经求出来了,直接调用存入

      pageBean.setCountAllPage(countAllPage);
      
    5. 首尾页,就是第一页(=1)和最后一页(countAllPage),不用传

    6. 上一页和下一页,用之前的currentPage做加减,不用传

    7. 每一页单独页数,用第一页和最后一页遍历即可,不用传

    继续在jsp中处理

    在中括号[ ]相应位置用el表达式取出相应的数据

    而点击跳转功能的实现,就是一个超链接,传servlet?=带参数即可

    这里需要对首尾页和中间的遍历做一点点处理。

    1. 首页和上一页加个判断,当在第一页时不需要显示

      <c:if test="${studentByPage.currentPage != 1}">
          <a href="StudentListPageServlet?currentPage=1">首页</a>
          |
          <a href="StudentListPageServlet?currentPage=${studentByPage.currentPage - 1}">上一页</a>
      </c:if>
      
    2. 尾页和下一页,当在最后一页时不需要显示

      <c:if test="${studentByPage.currentPage != studentByPage.countAllPage}">
          <a href="StudentListPageServlet?currentPage=${studentByPage.currentPage + 1}">下一页</a>
          |
          <a href="StudentListPageServlet?currentPage=${studentByPage.countAllPage}">尾页</a>
      </c:if>
      
    3. 对中间的页码处理,用一个遍历

      <c:forEach begin="1" end="${studentByPage.countAllPage}" var="i">
         ${i}
      </c:forEach>
      

      补上超链接

      <c:forEach begin="1" end="${studentByPage.countAllPage}" var="i">
              <a href="StudentListPageServlet?currentPage=${i}">${i}
      </c:forEach>
      

      在当前页时,不需要超链接,用if判断

      <c:forEach begin="1" end="${studentByPage.countAllPage}" var="i">
          <c:if test="${studentByPage.currentPage == i}">${i}</c:if>
          <c:if test="${studentByPage.currentPage != i}">
              <a href="StudentListPageServlet?currentPage=${i}">${i}</a>
          </c:if>
      </c:forEach>
      

    做好啦,完结撒花~

    未完待续

  • 相关阅读:
    盒子阴影——Box-shadow
    Flex布局
    常用正则表达式
    选择器
    上传头像功能
    利用百度地图API获取用户浏览器所在省市区
    Android Studio编译运行卡慢的解决方案
    Laravel5.5 解决时区设置差8个小时解决办法
    Git:远程代码与本地冲突常见解决方法
    vue-element-admin解决跨域问题
  • 原文地址:https://www.cnblogs.com/richardwlee/p/10316042.html
Copyright © 2020-2023  润新知