Web服务调用和SOA架构+部署docker容器

一、引言

1.1 实验目的

理解web Service和SOA架构,构建web 服务。要求:

1)构建校友录服务: 基于RESTful样式,对校友录进行插入、检索、修改、删除、统计等功能;同时,后端数据库使用Mybatis或者Hibernate进行操作。

2)把【校友录服务】部署在docker等容器中。

3)基于spring cloud在2)的基础上构建微服务,并进行部署

1.2 环境配置

  • 操作系统:Windows 10 X64,ubuntu虚拟机18.04.1
  • 编程工具:Intellij IDEA 2019.2×64,Navicat for MySQL
  • 数据库:Mysql(使用Mybatis框架操作)
  • 环境:Java jdk 1.8

二、构建校友录服务

2.1 创建数据库

创建数据库alumni_system,创建用户表user
在这里插入图片描述

2.2 项目后端代码

(1)后端代码结构如下
在这里插入图片描述
(2)Controller层代码
具体代码如下:UserController.java

@Controller
@RequestMapping("/course")
@ComponentScan(value = "course.service")
public class UserController {
    private UserService userService;

    @Autowired
    public UserController(UserService userService){
        this.userService = userService;
    }
    @RequestMapping("/addUser")
    public String toRegisterPage(){
        return "setInfo";
    }
    @RequestMapping("/setInfo")
    public String insert(HttpServletRequest request, Model model){
        userService.insert(request);
        model.addAttribute("msg", "注册成功!");
        return "redirect:/course/getAll";
    }
    @RequestMapping("/find")
    public String toGetUserPage(){
        return "findById";
    }
    @RequestMapping("/findById")
    public String findById(HttpServletRequest request,Model model){
        Integer id = Integer.parseInt(request.getParameter("userId"));
        User user =  userService.findById(id);
        model.addAttribute("userinfo",user);
        return "findAllUser";
    }
    @RequestMapping("/getAll")
    public String findAll(Model model){
        List<User> user =  userService.findAll();
        model.addAttribute("userinfo",user);
        return "findAllUser";
    }
    @RequestMapping("/updateUser")
    public String toupdatePage(HttpServletRequest request,Model model){
        Integer id = Integer.parseInt(request.getParameter("id"));
        model.addAttribute("id",id);
        return "updateInfo";
    }
    @RequestMapping("/updateInfo")
    public String update(HttpServletRequest request, Model model){
        Integer id = Integer.parseInt(request.getParameter("id"));
        userService.updateById(request,id);
        model.addAttribute("msg", "修改成功!");
        return "redirect:/course/getAll";
    }
    @RequestMapping("/deleteUser")
    public String deleteById(HttpServletRequest request){
        Integer id = Integer.parseInt(request.getParameter("id"));
        userService.deleteById(id);
        return "redirect:/course/getAll";
    }
}

(3)Entity层代码

具体代码如下:User.java

@Getter
@Setter
@ToString
public class User {
    private Integer id;

    private String name;

    private String sex;

    private String birthday;

    private Integer graduationyear;

    private String post;

    private String cellphone;

    private String email;

    private String wx;

    public User(){}

    public User(String name, String sex, String birthday, String graduationyear, String post, String cellphone, String email, String wx)
    {
        this.name = name;
        this.sex = sex;
        this.birthday = birthday;
        this.graduationyear = Integer.parseInt(graduationyear);
        this.post = post;
        this.cellphone = cellphone;
        this.email = email;
        this.wx = wx;
    }
}

(4)Mapper层代码

具体代码如下:UserMapper.java

@Mapper
@Repository
public interface UserMapper {
    int insert(User user);
    int updateById(@Param("updated") User updated, @Param("id") Integer id);
    User findAllById(@Param("id")Integer id);
    int deleteById(@Param("id")Integer id);
    List<User> findAll();
    
}

(5)Service层代码

具体代码如下:UserService.java

public interface UserService {

    public int insert(HttpServletRequest request);

    public int updateById(HttpServletRequest request,Integer id);

    public User findById(Integer id);

    public int deleteById(Integer id);

    public List<User> findAll();
}

UserServiceImpl.java

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Override
    public int insert(HttpServletRequest request) {
        User user = new User(request.getParameter("name"),request.getParameter("sex"),
                request.getParameter("birthday"),request.getParameter("graduationYear"),
                request.getParameter("post"),request.getParameter("cellphone"),
                request.getParameter("email"),request.getParameter("wx"));
        return userMapper.insert(user);
    }

    @Override
    public int updateById(HttpServletRequest request,Integer id){
        User user = new User(request.getParameter("name"),request.getParameter("sex"),
                request.getParameter("birthday"),request.getParameter("graduationYear"),
                request.getParameter("post"),request.getParameter("cellphone"),
                request.getParameter("email"),request.getParameter("wx"));
        return userMapper.updateById(user,id);
    }

    @Override
    public User findById(Integer id){
        return userMapper.findAllById(id);
    }

    @Override
    public int deleteById(Integer id){
        return userMapper.deleteById(id);
    }

    @Override
    public List<User> findAll(){
        return userMapper.findAll();
    }
}

(6)UserMapper.xml

后台使用mybatis的MybatisCodeHelper工具自动生成mapper的xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.course.Mapper.UserMapper">
  <resultMap id="BaseResultMap" type="com.example.course.Entity.User">
    <!--@mbg.generated-->
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="sex" jdbcType="VARCHAR" property="sex" />
    <result column="birthday" jdbcType="VARCHAR" property="birthday" />
    <result column="graduationYear" jdbcType="INTEGER" property="graduationyear" />
    <result column="post" jdbcType="VARCHAR" property="post" />
    <result column="cellphone" jdbcType="VARCHAR" property="cellphone" />
    <result column="email" jdbcType="VARCHAR" property="email" />
    <result column="wx" jdbcType="VARCHAR" property="wx" />
  </resultMap>
  <sql id="Base_Column_List">
    <!--@mbg.generated-->
    id, `name`, sex, birthday, graduationYear, post, cellphone, email, wx
  </sql>
  <insert id="insert" parameterType="com.example.course.Entity.User">
    <!--@mbg.generated-->
    insert into user (id, `name`, sex, 
      birthday, graduationYear, post, 
      cellphone, email, wx
      )
    values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{sex,jdbcType=VARCHAR}, 
      #{birthday,jdbcType=VARCHAR}, #{graduationyear,jdbcType=INTEGER}, #{post,jdbcType=VARCHAR},
      #{cellphone,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR}, #{wx,jdbcType=VARCHAR}
      )
  </insert>

<!--auto generated by MybatisCodeHelper on 2020-05-31-->
  <update id="updateById">
    update user
    <set>
      <if test="updated.id != null">
        id = #{updated.id,jdbcType=INTEGER},
      </if>
      <if test="updated.name != null">
        name = #{updated.name,jdbcType=VARCHAR},
      </if>
      <if test="updated.sex != null">
        sex = #{updated.sex,jdbcType=VARCHAR},
      </if>
      <if test="updated.birthday != null">
        birthday = #{updated.birthday,jdbcType=VARCHAR},
      </if>
      <if test="updated.graduationyear != null">
        graduationYear = #{updated.graduationyear,jdbcType=INTEGER},
      </if>
      <if test="updated.post != null">
        post = #{updated.post,jdbcType=VARCHAR},
      </if>
      <if test="updated.cellphone != null">
        cellphone = #{updated.cellphone,jdbcType=VARCHAR},
      </if>
      <if test="updated.email != null">
        email = #{updated.email,jdbcType=VARCHAR},
      </if>
      <if test="updated.wx != null">
        wx = #{updated.wx,jdbcType=VARCHAR},
      </if>
    </set>
    where id=#{id,jdbcType=INTEGER}
  </update>

<!--auto generated by MybatisCodeHelper on 2020-05-31-->
  <select id="findAllById" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List"/>
    from user
    where id=#{id,jdbcType=INTEGER}
  </select>

<!--auto generated by MybatisCodeHelper on 2020-05-31-->
  <delete id="deleteById">
    delete from user
    where id=#{id,jdbcType=INTEGER}
  </delete>

<!--auto generated by MybatisCodeHelper on 2020-06-01-->
  <select id="findAll" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from user
    </select>
</mapper>

2.3 项目前端代码

前端使用bootstrap框架,代码结构如下:
在这里插入图片描述

2.4 运行结果

(1)查看所有校友信息

在这里插入图片描述
(2)检索校友信息
按照校友ID检索校友信息:
在这里插入图片描述
跳转到搜索页面,输入校友ID:
在这里插入图片描述
返回搜索结果:
在这里插入图片描述
(3)插入校友信息
点击导航栏的“新增校友”:
在这里插入图片描述
进入新增校友信息页面:
在这里插入图片描述
输入要插入的校友信息:
在这里插入图片描述
点击“确认注册”返回校友信息列表,发现信息插入成功:
在这里插入图片描述
(4)删除校友信息
点击校友信息最后一栏的“删除”按钮:
在这里插入图片描述
提示是否删除:
在这里插入图片描述
点击“确定”,删除成功后返回校友信息列表,发现删除信息成功:
在这里插入图片描述

三、把【校友录服务】部署在docker容器中

本次实验我将构建好的校友录服务部署在了我本地ubuntu虚拟机的docker容器中,并可以在虚拟机上运行此服务,我的部署流程如下:

3.1 在ubuntu虚拟机上安装docker容器

(1)打开ubuntu终端,运行安装docker命令

sudo apt-get install -y docker.io

(2)等待安装完毕,使用下面的命令启动 docker:

sudo systemctl start docker

(3)运行系统引导时启用 docker,命令:

sudo systemctl enable docker

(4)检验是否安装并启动成功docker:

跑一下hello-world镜像看能否启动成功,使用指令docker run hello-world,若能输出“Hello from Docker!”,则说明安装并启动成功,可以运行镜像了
在这里插入图片描述

3.2 在docker中安装tomcat和mysql容器

(1)安装tomcat指令:

sudo docker pull tomcat

(2)安装mysql指令(默认安装版本为5.7):

sudo docker pull mysql

(3)安装好后,我们使用sudo docker images指令查看安装好的tomcat和mysql

在这里插入图片描述

3.3 在docker中启动mysql并建立数据库和表

(1)使用指令启动mysql数据库服务
sudo docker run -itd --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7 --character-set-server=utf8 --collation-server=utf8_unicode_ci

解释上面命令的含义:

  • run -itd:在docker中运行一个带交互式的且能后台运行的容器。
  • –name mysql:给容器命名为mysql,注意name前面有两个小横杠,你也可以自己随意命名。
  • -p 3306:3306:这里是指将容器的3306端口映射到主机的3306端口,冒号前面指的是主机,后面指的是容器。
  • -e MY_ROOT_PASSWORD=123456:这行命令的意思是在创建mysql容器的时候在容器中创建一个root用户,密码是123456,要是不想用123456,把它改成你想要的就可以了。
  • –character-set-server=utf8 --collation-server=utf8_unicode_ci:解决docker中mysql数据库中文乱码问题

(2)进入mysql容器并登陆

执行指令

sudo docker exec -it mysql bash

再执行

mysql -u root -p

输入密码(123456)

(3)创建数据库alumni_system

create database alumni_system

(4)利用sql文件建表

a)sql文件可以由Navicat导出并存储,复制到ubuntu虚拟机/home文件夹下
在这里插入图片描述
b)首先得到mysql容器的全ID,执行指令:

sudo docker inspect  -f '{{.Id}}' mysql

在这里插入图片描述
c)将sql文件上传到docker中,执行指令:

sudo  docker cp /home/jade/alumni_system.sql         
b38fcda698d8f2fdceb980c3bf8b26372b3aad10016f65c432f791188d1fefaa:/tmp/

d)选中数据库alumni_system,在mysql中执行语句:

mysql>use alumni_system

e)将sql插入数据库,执行语句:

mysql>source /tmp/alumni_system.sql

插入成功如下,使用desc user查看表:
在这里插入图片描述
(5)查看mysql的ip地址,修改spring项目中application.yml(或application.properties)的数据库ip地址
在ubuntu命令行中输入以下指令查看IP地址:

sudo docker inspect mysql

在这里插入图片描述
图上可以看到,这里的ip是172.17.0.2,也就是说我们如果部署web应用,就要在工程文件中指定访问的数据库的ip地址为172.17.0.2,这样web应用部署在tomcat上才会去读取mysql中的数据。我这里的工程文件如下图所示:
在这里插入图片描述
将工程文件中连接数据库的配置信息改成我们容器的ip地址即可。

3.4 springBoot项目准备(打成jar包)

(1)在pom.xml中添加docker的插件(添加代码后maven项目会自动导入)
主要用了docker-maven-plugin这个maven插件

<!--jar包命名-->
<name>course</name>
<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<!-- docker 插件 begin -->
			<plugin>
				<groupId>com.spotify</groupId>
				<artifactId>docker-maven-plugin</artifactId>
				<version>1.0.0</version>
				<configuration>
              <imageName>${docker.image.prefix}/${project.artifactId}</imageName>
					<resources>
						<resource>
							<targetPath>/</targetPath>
							<directory>${project.build.directory}</directory>
							<include>${project.build.finalName}.jar</include>
						</resource>
					</resources>
				</configuration>
			</plugin>
			<!-- docker 插件 end -->
		</plugins>
<finalName>course</finalName><!--打包后文件名称-->
</build>

(2)点击右侧maven状态栏中的Lifecycle的install进行打包成jar包
在这里插入图片描述
生成的jar包在target目录下:
在这里插入图片描述
(3)把生成的jar包复制到ubuntu虚拟机上,我这里复制到新建的maven目录下

在这里插入图片描述
(4)Dockerfile文件配置
在ubuntu上和复制的jar包同目录下,新建一个Dockerfile文件,文件内容如下:

FROM carsharing/alpine-oraclejdk8-bash  
VOLUME /tmp  
ADD docker-study.jar app.jar  
ENTRYPOINT ["java","-jar","/app.jar"]  

以上代码解释:
FROM 指定此docker需要依赖的docker image,由于这是一个spring boot项目,故要运行一个spring boot项目,必须得要有jdk,而上面写的carsharing/alpine-oraclejdk8-bash这个镜像中包含了一套拥有jdk的环境,可以此环境中运行java程序

VOLUME 用来指定docker运行的临时目录。它将在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp。/tmp目录用来持久化到 Docker 数据文件夹,因为 Spring Boot 使用的内嵌 Tomcat 容器默认使用/tmp作为工作目录

ADD 是将pom.xml中的targetPath下的docker-study.jar复制到容器中,并命名为app.jar

ENTRYPOINT 指定了容器启动时要执行的命令。那么这里就是执行java -jar /app.jar的意思,意思就是去运行这个springBoot项目了

注:如果carsharing/alpine-oraclejdk8-bash报错,执行以下指令:

docker pull carsharing/alpine-oraclejdk8-bash

3.5 建立course.jar的镜像并运行

(1)建立course的imgaes,执行指令:

sudo docker build -t course:latest .

(2)查看建立的course镜像,执行指令:
sudo docker images
在这里插入图片描述
(3)启动course镜像,执行指令:

sudo docker run -d -p 8080:8080 course

(4)查看运行的镜像,执行指令:
sudo docker ps
在这里插入图片描述
可以看到mysql和course正在运行,到此docker镜像上的spring项目就部署好了,我们可以来验证一下

3.6 ubuntu中docker镜像上的spring项目运行情况

(1)查看所有校友信息
在这里插入图片描述
(2)插入校友信息

输入要插入的校友信息:
在这里插入图片描述
点击“确认注册”返回校友信息列表,发现信息插入成功:
在这里插入图片描述
(3)检索校友信息

跳转到搜索页面,输入校友ID:
在这里插入图片描述
返回搜索结果:
在这里插入图片描述
(4)删除校友信息
点击校友信息最后一栏的“删除”按钮,提示是否删除:
在这里插入图片描述
点击“确定”,删除成功后返回校友信息列表,发现删除信息成功:
在这里插入图片描述

四、构建course微服务,并进行部署

在第三步的基础上,配置主机ip端口和虚拟机的ip端口,使得主机可以访问部署在ubuntu虚拟机上的docker中的course服务

4.1 配置虚拟机的ip和本机ip在同一个局域网下,使得主机和虚拟机可以互相ping通

(1)使用ifconfig命令,查看ubuntu虚拟机的ip地址
在这里插入图片描述
可以看到虚拟机的IP地址为192.168.192.130
(2)win下cmd输入ipconfig查看vm8的ip是不是和linux的ip相同
在这里插入图片描述
VM8的ip如果和虚拟机的IP地址不在同一局域网则需要配置(上面是我已经配置好的)

(3)如果不同,则配置成相同局域网,具体操作如下:

打开“网络和Internet设置”,点击更改适配器选项
在这里插入图片描述
右键点击VMnet8,选择属性,选中TCP/IPv4,选择属性
在这里插入图片描述
修改为和虚拟机相同局域网ip,点击确定,重启VMnet8
在这里插入图片描述
主机再ping虚拟机成功
在这里插入图片描述
虚拟机也可以ping通主机
在这里插入图片描述

4.2 配置主机和虚拟机的端口,使得主机可以访问虚拟机上的docker中的web服务

(1)先关闭虚拟机的防火墙,执行sudo ufw disable命令

(2)配置端口转发
打开VMware虚拟机的虚拟网络编辑器,通过编辑->虚拟网络编辑器进入

选择VMnet8,点击NAT设置
在这里插入图片描述
添加端口转发,使得本机的8080端口可以访问虚拟机的8080端口
在这里插入图片描述
(3)配置完毕后,在本机可以访问虚拟机中docker里的微服务course
在主机上访问http://localhost:8080/course/getAll 显示出校友信息
在这里插入图片描述
验证其他插入、修改、搜索和删除等功能一切正常,至此在虚拟机上的docker中部署微服务并能使主机访问的任务已全部完成

五、总结

5.1 问题总结

(1)在使用sql文件导入docker的数据库中时,遇到了错误[ERR] 1273 - Unknown collation: ‘utf8mb4_0900_ai_ci’,这个错误的原因是生成转储文件的数据库版本为8.0,要导入sql文件的数据库版本为5.7,因为是高版本导入到低版本,引起1273错误。解决方法是打开sql文件,将文件中的所有utf8mb4_0900_ai_ci替换为utf8_general_ci,utf8mb4替换为utf8。保存后再次运行sql文件,运行成功。

(2)在编译Dockerfile文件时,一开始写的是From frolvlad/alpine-oraclejdk8:slim,但是遇到了错误pull access denied for frolvlad/alpine-oraclejdk8, repository does not exist or may require ',后来修改为FROM carsharing/alpine-oraclejdk8-bash,并执行指令sudo docker pull carsharing/alpine-oraclejdk8-bash得以解决。

(3)使用Docker部署Mysql时中文乱码问题,在数据库中使用select语句查看数据显示中文正确,但在前端显示和插入中文均为乱码。解决方法:启动mysql时在命令后加入–character-set-server=utf8 --collation-server=utf8_unicode_ci,从而解决中文乱码问题。

5.2 收获

  通过本次实验,我理解了web Service和SOA架构,并学会了构建web服务和使用docker容器部署服务,在编写【校友录服务】的过程中进一步熟悉了使用IDEA创建maven项目和使用后台的mybatis框架进行数据库的操作,在学习的过程中不断发现问题并解决问题,这个过程是煎熬的但问题得到解决的一瞬也是快乐的,总之对于web服务调用的实验我学到了很多东西。

六、参考链接

[1] spring boot 部署到docker容器

[2] 在 Ubuntu 上如何安装Docker及基本用法

[3] 将springBoot项目部署到docker入门实例

[4] 关于如何在docker中利用tomcat和MySQL容器部署java web应用的详细步骤

[5] 主机不能访问虚拟机中的web服务【解决方案】

七、项目github链接

https://github.com/JadeShaw1016/course

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值