Windows VMWare Centos Docker部署Springboot + mybatis + MySql应用

发布于:2025-07-02 ⋅ 阅读:(27) ⋅ 点赞:(0)

前置文章

Windows VMWare Centos环境下安装Docker并配置MySqlhttps://blog.csdn.net/u013224722/article/details/148928081

Windows VMWare Centos Docker部署Springboot应用https://blog.csdn.net/u013224722/article/details/148958480

Windows VMWare Centos Docker部署Nginx并配置对Springboot应用的访问代理https://blog.csdn.net/u013224722/article/details/149007158

一、MySql 建库建表

1、新建数据库

        通过Widnows宿主机安装的数据库管理工具“Navicat Premium”连上在VMWare Centos Docker中创建的MySQL数据库。新建一个数据库‘duel_db’。

2、新建数据表

新建managers表, 用于系统管理员的登录。

新建表,用于存储用户信息

新建files表, 用于上传文档信息的存储

二、 Springboot应用使用MySql

1、在IDEA中连接数据库方式参考

查看VMware Centos的ip

在IDEA右侧的Database面板新建Data Source

2、Springboot应用配置mybatis

2.1 修改pom.xml

打开pom.xml文件,添加MySQL  mybatis以及注解相关依赖

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.4</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

pom.xml文件修改Build,用于mybatis自动生成数据表对象以及mapper。 

  <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.4.2</version>
                <dependencies>
                    <dependency>
                        <groupId>com.mysql</groupId>
                        <artifactId>mysql-connector-j</artifactId>
                        <version>9.2.0</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
                    <overwrite>true</overwrite>
                    <verbose>true</verbose>
                </configuration>
            </plugin>
        </plugins>
    </build>

2.2 修改application.properties 

新增数据库连接相关属性,添加mybatis相关设置。

# MySql
spring.datasource.url=jdbc:mysql://192.168.23.134:3306/duel_db?useSSL=false
spring.datasource.username=root
spring.datasource.password=pwd123456
spring.datasource.driver-class-name= com.mysql.cj.jdbc.Driver

# Mybatis
mybatis.mapper-locations=classpath:mapper/*.xml

 2.3 创建mybatis相关配置文件

在resources文件夹下新建 generatorConfig.xml文件,并设置model、mapper相关文件的自动存储目录。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <!-- 引入 application.properties 中的配置(可选) -->
    <properties resource="application.properties"/>

    <!-- 数据库驱动路径(如果未通过Maven依赖管理) -->
    <!-- <classPathEntry location="/path/to/mysql-connector-java-8.0.33.jar"/> -->

    <context id="duel_db" targetRuntime="MyBatis3">
        <!-- 生成的Java文件编码 -->
        <property name="javaFileEncoding" value="UTF-8"/>

        <!-- 生成的Java文件的注释 -->
        <commentGenerator>
            <!-- 注释配置:不生成注释 -->
            <property name="suppressAllComments" value="true"/>
            <!-- 生成注释 -->
            <!--            <property name="addRemarkComments" value="true"/>-->
        </commentGenerator>

        <!-- 数据库连接信息 -->
        <jdbcConnection driverClass="${spring.datasource.driver-class-name}"
                        connectionURL="${spring.datasource.url}"
                        userId="${spring.datasource.username}"
                        password="${spring.datasource.password}">
        </jdbcConnection>

        <!-- Java模型生成配置 -->
        <javaModelGenerator targetPackage="com.duelapi.model" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>


        <!-- 生成 SQL Map XML 文件的配置 -->
        <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>

        <!-- Mapper接口生成配置 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.duelapi.mapper" targetProject="src/main/java">
            <property name="enableSubPackages" value="false"/>
        </javaClientGenerator>


        <table schema="Local" tableName="files" domainObjectName="FileRecord"
               enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
               enableSelectByExample="false" selectByExampleQueryId="false"></table>
        <table schema="Local" tableName="members" domainObjectName="MemberRecord"
               enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
               enableSelectByExample="false" selectByExampleQueryId="false"></table>
        <table schema="Local" tableName="managers" domainObjectName="ManagerRecord"
               enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
               enableSelectByExample="false" selectByExampleQueryId="false"></table>
    </context>
</generatorConfiguration>

修改启动类,新增@MapperScan("com.duelapi.mapper")

package com.duelapi;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.duelapi.mapper")
public class DuelApiApplication {

    public static void main(String[] args) {
        SpringApplication.run(DuelApiApplication.class, args);
    }

}

2.4 生成Model及Mapper文件 

在右侧Maven面板,双击 mybatis-generator,自动执行生成操作。

 2.5 新增数据库查询语句

ManagerRecordMapper.java、  ManagerRecordMapper.xml中新增查询管理员的SQL

 ManagerRecord selectByAccount(String account);
  <select id="selectByAccount" parameterType="java.lang.String" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from managers
    where account = #{account,jdbcType=VARCHAR}
  </select>

ManagerRecordMapper.java、  ManagerRecordMapper.xml中新增查询member的SQL 

    List<MemberRecord> selectAll();
  <select id="selectAll" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from members
  </select>

 3、新增MySQL交互相关接口

 MemberRecord.java 新增转键值对的方法。

    public Map<String, Object> toMap(){
        Map<String, Object> result = new HashMap<>();
        result.put("id", this.getId());
        result.put("memberName", this.getMemberName());
        result.put("account", this.getAccount());
        return result;
    }

  新建ManageController.java

package com.duelapi.controller;

import com.duelapi.model.MemberRecord;
import com.duelapi.service.IManageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@Controller
@RequestMapping("/manage")
public class ManageController {

    private IManageService manageService;

    @Autowired
    public ManageController(IManageService manageService){
        this.manageService = manageService;
    }

    @RequestMapping(value = "/managerLogin", method = RequestMethod.GET)
    @ResponseBody
    public Map<String, Object> managerLogin(@RequestParam(value = "account") String account,
                                           @RequestParam(value = "pwd") String pwd) {
        return this.manageService.managerLogin(account, pwd);
    }

    @RequestMapping(value = "/getMemberList", method = RequestMethod.GET)
    @ResponseBody
    public Map<String, Object> getMemberList() {
        return this.manageService.getMemberList();
    }

    @RequestMapping(value = "/addMember", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> addMember(@RequestBody MemberRecord memberInfo) {
        return this.manageService.addMember(memberInfo);
    }

    @RequestMapping(value = "/deleteMember", method = RequestMethod.GET)
    @ResponseBody
    public Map<String, Object> deleteMember(@RequestParam(value = "id") Integer id) {
        return this.manageService.deleteMember(id);
    }
}

新建 interface   IManageService.java 

package com.duelapi.service;

import com.duelapi.model.MemberRecord;

import java.util.Map;

public interface IManageService {
    Map<String, Object> managerLogin(String account, String pwd);

    Map<String, Object> addMember(MemberRecord memberRec);

    Map<String, Object> deleteMember(Integer id);

    Map<String, Object> getMemberList();
}

新建 ManageService.java 实现 IManageService.java 

package com.duelapi.serviceimpl;

import com.duelapi.mapper.ManagerRecordMapper;
import com.duelapi.mapper.MemberRecordMapper;
import com.duelapi.model.ManagerRecord;
import com.duelapi.model.MemberRecord;
import com.duelapi.service.IManageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class ManageService implements IManageService {

    private ManagerRecordMapper managerMapper;
    private MemberRecordMapper memberMapper;

    @Autowired
    public ManageService(ManagerRecordMapper managerMapper,
                         MemberRecordMapper memberMapper)
    {
        this.managerMapper = managerMapper;
        this.memberMapper = memberMapper;
    }

    @Override
    public Map<String, Object> managerLogin(String account, String pwd) {

        Map<String, Object> resultMap = new HashMap<>();
        ManagerRecord rec = this.managerMapper.selectByAccount(account);
        if(rec != null)
        {
            if( rec.getPwd().equals(pwd)) {
                resultMap.put("status", "1");
                resultMap.put("msg", "success");
            }
            else {
                resultMap.put("status", "0");
                resultMap.put("msg", "密码错误");
            }
        }
        else
        {
            resultMap.put("status", "0");
            resultMap.put("msg", "管理员账户不存在");
        }
        return resultMap;
    }

    @Override
    public Map<String, Object> addMember(MemberRecord memberRec) {
        Map<String, Object> resultMap = new HashMap<>();

        int nFlag = this.memberMapper.insertSelective(memberRec);
        if(nFlag == 1){
            resultMap.put("status", "1");
            resultMap.put("msg", "success");
        }
        else{
            resultMap.put("status", "0");
            resultMap.put("msg", "数据保存至数据库出错!");
        }
        return resultMap;
    }

    @Override
    public Map<String, Object> deleteMember(Integer id) {
        Map<String, Object> resultMap = new HashMap<>();

        int nFlag = this.memberMapper.deleteByPrimaryKey(id);
        if(nFlag == 1){
            resultMap.put("status", "1");
            resultMap.put("msg", "success");
        }
        else{
            resultMap.put("status", "0");
            resultMap.put("msg", "数据库删除时出错!");
        }
        return resultMap;
    }

    @Override
    public Map<String, Object> getMemberList() {
        List<MemberRecord> arrRecords = this.memberMapper.selectAll();

        List<Map<String, Object>> ltMaps = new ArrayList<>();
        int nAmount = 0;
        if (arrRecords != null && !arrRecords.isEmpty()) {
            ltMaps = arrRecords.stream().map(vo -> vo.toMap()).collect(Collectors.toList());
            nAmount = arrRecords.size();
        }

        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("rows", ltMaps);
        resultMap.put("total", nAmount);
        return resultMap;
    }
}

创建完成后的文件目录如下 

 

启动测试 

浏览器直接访问接口进行测试,测试通过。

4、前后端分离测试 

1、新建一个H5项目,添加JQuery、bootstrap、bootstrap-table引用

const.js 文件中定义接口访问地址

constUtils = {
    Server:"http://localhost:8093/",
};

index.html中实现对接口的调用及测试结果显示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试</title>

    <link href="./plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet">
    <link href="./plugins/bootstrap/css/bootstrap-table.min.css" rel="stylesheet">
</head>
<body>

<div style="max-width: 720px; margin: 30px auto">
    <div id="tabToolbar"></div>
    <table id="tabMain" data-toolbar="#tabToolbar"></table>

    <div style="margin-top: 40px; background: #e7e7e7; padding: 30px">
        <h4>新增测试</h4>

        <div style="padding: 20px 0">
            <label style="display: block"> 姓名:
                <input type="text" id="txtName">
            </label>
            <label style="display: block"> 账号:
                <input type="text" id="txtAccount">
            </label>
            <label style="display: block"> 密码:
                <input type="password" id="txtPwd">
            </label>
        </div>

        <button id="btnAddManager" type="button" class="btn btn-primary" onclick="addNewMember()">
            提交
        </button>
    </div>
</div>

<script type="text/javascript" src="js/const.js"></script>
<script type="text/javascript" src="js/jquery.min.js?v2.1.4"></script>
<script src="./plugins/bootstrap/js/bootstrap.min.js"></script>
<script src="./plugins/bootstrap/js/bootstrap-table.min.js"></script>

<script>

    $(document).ready(function () {
        doUpdateTab();
    });

    function doUpdateTab() {
        $('#tabMain').bootstrapTable('destroy');
        $('#tabMain').bootstrapTable({
            method: 'get',
            toolbar: '#tabToolbar',    //工具按钮用哪个容器
            striped: true,      //是否显示行间隔色
            cache: false,      //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)
            pagination: true,     //是否显示分页(*)
            sortable: false,      //是否启用排序
            sortOrder: "desc",     //排序方式
            pageNumber: 1,      //初始化加载第一页,默认第一页
            pageSize: 50,      //每页的记录行数(*)
            pageList: [10, 25, 50, 100],  //可供选择的每页的行数(*)
            url: constUtils.Server + "manage/getMemberList",//这个接口需要处理bootstrap table传递的固定参数
            queryParamsType: 'undefined', //默认值为 'limit' ,在默认情况下 传给服务端的参数为:offset,limit,sort
            queryParams: function queryParams(queryParams) {   //设置查询参数
                return {};
            },//前端调用服务时,会默认传递上边提到的参数,如果需要添加自定义参数,可以自定义一个函数返回请求参数
            sidePagination: "server",   //分页方式:client客户端分页,server服务端分页(*)
            search: true,      //是否显示表格搜索,此搜索是客户端搜索,不会进服务端,所以,个人感觉意义不大
            strictSearch: false,
            showColumns: true,     //是否显示所有的列
            showRefresh: true,     //是否显示刷新按钮
            minimumCountColumns: 2,    //最少允许的列数
            clickToSelect: true,    //是否启用点击选中行
            searchOnEnterKey: true,
            columns: [
                {
                    title: '序号',
                    align: 'center',
                    formatter: function (value, row, index) {
                        return index + 1;
                    }
                },
                {
                    field: 'memberName',
                    title: '姓名',
                    searchable: true,
                    align: 'center'
                },
                {
                    field: 'account',
                    title: '账号',
                    searchable: true,
                    align: 'center'
                },

                {
                    title: '操作',
                    align: 'center',
                    searchable: false,
                    formatter: function (value, row, index) {
                        return '<a class="btn" style="margin-left: 10px;" ' +
                            ' onclick="deleteRecord(\'' + row.id + '\')">删除</a>';
                    }
                }
            ],
            onLoadSuccess: function (data) {  //加载成功时执行
                console.log(data)
            },
            onLoadError: function (err) {
                console.log(err);

            },
            showToggle: false,    //是否显示详细视图和列表视图的切换按钮
            cardView: false,     //是否显示详细视图
            detailView: false,     //是否显示父子表
        });
    }

    function deleteRecord(id) {
        $.ajax({
            method: "GET",
            url: constUtils.Server + "manage/deleteMember",
            data: {
                id:id
            },
            cache: false,
            dataType: "json",
            contentType: "application/json",
            async: false, //同步
            success: function (res) {
                console.log(res);
                $('#tabMain').bootstrapTable('refresh');
            },
            error: function (err) {
                console.log(err);
            }
        });
    }

    function addNewMember(){
        let memberInfo ={
            memberName: $('#txtName').val(),
            account: $('#txtAccount').val(),
            pwd: $('#txtPwd').val()
        };
        console.log(memberInfo);

        $.ajax({
            method: "POST",
            url: constUtils.Server + "manage/addMember",
            data: JSON.stringify(memberInfo),
            cache: false,
            dataType: "json",
            contentType: "application/json",
            async: false, //同步
            success: function (res) {
               console.log(res);
                $('#tabMain').bootstrapTable('refresh');
            },
            error: function (err) {
                console.log(err);
            }
        });
    }

</script>

</body>
</html>

浏览器中加载H5进行测试

初始运行,Member 列表为空。

填写Member信息并提交

 提交后,表格中显示了新增的member,接口实现成功。 正常对MySql进行读写。

三、发布至Docker

1、发布jar包并部署至Docker

       Idea 中pom.xml修改version为 0.0.2,将springboot应用打包为 dapi-0.0.2.jar. 我使用的打包方式前置文章中有介绍。 将Jar包拷贝进VMWare Centos系统中。

修改Dockerfile 

#Dockerfile 内容
 
FROM openjdk:24
 
# 后端工作目录
VOLUME /app
 
# 后端jar包名称
COPY dapi-0.0.2.jar /app/dapi.jar
 
# 后端项目的端口号
EXPOSE 8093
 
#启动时指令
ENTRYPOINT ["java", "-jar", "/app/dapi.jar"]

移除Docker中的dapi-0.0.1版本 

duel@localhost:~/workspace$ sudo docker ps -a
duel@localhost:~/workspace$ sudo docker stop dapi
duel@localhost:~/workspace$ sudo docker rm dapi
duel@localhost:~/workspace$ sudo docker ps -a
duel@localhost:~/workspace$ sudo docker images
duel@localhost:~/workspace$ sudo docker rmi dapi:1.0.0

安装上0.0.2版本 

#执行Image安装
 
$ sudo docker build -t dapi:0.0.2 .
 
#启动容器并映射端口
 
$ sudo docker run --name dapi -p 8093:8093 -d dapi:0.0.2 --restart=always

Terminal终端日志如下: 

VMWare Centos 打开Firefox浏览器测试接口,成功。

切换Nginx代理的端口号 【38081】,测试成功。我的Nginx的配置可在前置文章中查看

2、发布静态网页至Docker

Windows 中 用 Webstorm创建的前端测试H5,拷贝至VMWare Center Os 中

VMWare Centos 系统下存放位置如下:

移除Nginx容器,重新创建Nginx。

Nginx配置方式可参考我的前置文章:

Windows VMWare Centos Docker部署Nginx并配置对Springboot应用的访问代理-CSDN博客

VMWare Centos 打开Firefox浏览器测试接口,成功。

3、Windows宿主机测试

     回到Windows宿主机,打开Chrome浏览器, 通过虚拟机Centos的ip + Docker中配置的Nginx的代理端口号对静态网页和接口分别进行测试。

接口访问成功,静态网页访问成功,网页调用接口加载数据失败:

查找原因:localhost 仅在 VMWare Centos 系统内部有效

修改接口地址后,重新发布

测试成功

至此,前后端分类的 Html  + Springboot + mybatis + MySql + Nginx 项目在VMWare Centos Docker中完整实践完成。

下一篇,继续实践 Springboot 处理文件上传后在Docker中的存储以及返回 http://upload_file_web_url 相关功能。


网站公告

今日签到

点亮在社区的每一天
去签到