案例说明:
SpringBoot整合SSM与Docker的微服务,并对简单的一张表使用RESTFul Api进行CRUD操作 ,然后打包成docke镜像在docker容器中运行,为其他应用提供服务的案例。
声明:因为没有与Spring Cloud体系整合,这里说微服务可能不太恰当。大牛请绕过,这里只是作为学习过程中的小笔记,大神们感觉有不合理的地方烦请指点一二。
# 1.创建数据库springBootSsm
create schema if not exists springBootSsm collate utf8_general_ci;
# 2. 切换到springBootSsm数据库
use springBootSsm;
# 3. 创建一张tb_user表
create table if not exists tb_user
(
id int auto_increment comment '自增主键' primary key,
user_name varchar(50) null comment '用户名',
password varchar(50) null comment '密码',
email varchar(50) null comment '邮箱'
);
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.4.RELEASEversion>
<relativePath/>
parent>
<groupId>com.yuangroupId>
<artifactId>springboot-ssmartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>springboot-ssmname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
<dockerHost>http://192.168.31.176:2375dockerHost>
<dockerImageTag.version>1.0dockerImageTag.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.0.1version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.9.2version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
<plugin>
<groupId>com.spotifygroupId>
<artifactId>docker-maven-pluginartifactId>
<version>1.2.0version>
<configuration>
<imageName>spring-boot-ssmimageName>
<baseImage>javabaseImage>
<entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]entryPoint>
<resources>
<resource>
<targetPath>/targetPath>
<directory>${project.build.directory}directory>
<include>${project.build.finalName}.jarinclude>
resource>
resources>
<imageTags>
<imageTag>${project.version}imageTag>
<imageTag>${dockerImageTag.version}imageTag>
<imageTag>latestimageTag>
imageTags>
configuration>
plugin>
plugins>
build>
project>
在com.yuan.springbootssm.model
包下新建User.java,内容如下
package com.yuan.springbootssm.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {
private Integer id;
private String userName;
private String password;
private String email;
}
在com.yuan.springbootssm.mapper
包下新建一个接口,名称为UserMapper.java,内容如下
package com.yuan.springbootssm.mapper;
import com.yuan.springbootssm.model.User;
import java.util.List;
public interface UserMapper {
User getUser(Integer id);//根据id获取信息
boolean addUser(User user);//新增
boolean modifyUser(User user);//修改
boolean deleteUser(Integer id);//根据id删除
List<User> getAll();//获取所有
}
在com.yuan.springbootssm.service
包下新建一个类,名称为UserService.java
package com.yuan.springbootssm.service;
import com.yuan.springbootssm.mapper.UserMapper;
import com.yuan.springbootssm.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User getUser(Integer id){
return userMapper.getUser(id);
}
public boolean addUser(User user){
return userMapper.addUser(user);
}
public boolean modifyUser(User user){
return userMapper.modifyUser(user);
}
public boolean deleteUser(Integer id){
return userMapper.deleteUser(id);
}
public List<User> getAll(){
return userMapper.getAll();
}
}
在com.yuan.springbootssm.controller
包下新建一个类,名称为UserController.java
package com.yuan.springbootssm.controller;
import com.yuan.springbootssm.model.User;
import com.yuan.springbootssm.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class UserController {
@Autowired
private UserService userService;
@Resource
DataSource dataSource;//数据源信息
/**
* 获取默认的数据源信息
* @return
* @throws SQLException
*/
@ResponseBody
@GetMapping("/dataSource/get")
public Map<String,Object> getDefaultDataSource() throws SQLException {
Map<String,Object> map = new HashMap<>();
map.put("dataSource",dataSource.getClass());
map.put("jdbcURL",dataSource.getConnection().getMetaData().getURL());
System.out.println("默认的数据源为:"+dataSource.getClass());
System.out.println("连接地址:"+dataSource.getConnection().getMetaData().getURL());
return map;
}
/**
* 根据id获取信息
* @param id
* @return
* @throws SQLException
*/
@ResponseBody
@GetMapping("/user/get/{id}")
public User getUser(@PathVariable("id") Integer id){
return userService.getUser(id);
}
/**
* 获取所有信息
* @return
*/
@ResponseBody
@GetMapping("/user/list")
public List<User> getAll(){
return userService.getAll();
}
/**
* 新增信息
* @param user
* @return
*/
@ResponseBody
@PostMapping("/user/add")
public boolean addUser(@RequestBody User user){
return userService.addUser(user);
}
/**
* 修改信息
* @param user
* @return
*/
@ResponseBody
@PutMapping("/user/put")
public boolean modifyUser(@RequestBody User user){
return userService.modifyUser(user);
}
/**
* 删除信息
* @param id
* @return
*/
@ResponseBody
@DeleteMapping("/user/delete/{id}")
public boolean deleteUser(@PathVariable("id") Integer id){
return userService.deleteUser(id);
}
}
@MapperCan
注解@EnableSwagger2
注解package com.yuan.springbootssm;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@SpringBootApplication
@MapperScan("com.yuan.springbootssm.mapper")//自动扫描的Mapper包,如果这里不指定,则需要在每个Mapper接口中添加@Mapper主键(这两种方法二选一)
@EnableSwagger2 //开启Swagger2功能,方便测试RestApi
public class SpringbootSsmApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootSsmApplication.class, args);
}
}
新建mappers
目录,并创建Mybatis的对象关映射文件新建error目录,并创建4xx.html与5xx.html
文件来处理异常
<mapper namespace="com.yuan.springbootssm.mapper.UserMapper">
<resultMap id="BaseResultMap" type="com.yuan.springbootssm.model.User">
<id column="id" jdbcType="INTEGER" property="id"/>
<result column="user_name" jdbcType="VARCHAR" property="userName"/>
<result column="password" jdbcType="VARCHAR" property="password"/>
<result column="email" jdbcType="VARCHAR" property="email"/>
resultMap>
<select id="getUser" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select * from tb_user t where t.id = #{id}
select>
<select id="getAll" resultMap="BaseResultMap">
select * from tb_user t
select>
<insert id="addUser" parameterType="user">
insert into tb_user values(default,#{userName},#{password},#{email})
insert>
<update id="modifyUser" parameterType="user">
update tb_user set user_name=#{userName},password=#{password},email=#{email} where id = #{id}
update>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from tb_user where id = #{id}
delete>
mapper>
这里为了熟悉yml语法,使用application.yml配置文件,而未使用application.properties文件进行配置,二者选那个都行,里面的配置内容除了语法不一样外,其它都一样
# 数据源配置,这里使用springboot默认自动配置的数据源
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: yuan
url: jdbc:mysql://192.168.31.176:3306/springBootSsm?characterEncoding=utf8&useSSL=false
# Mybatis相关配置
mybatis:
# 对象别名包
type-aliases-package: com.yuan.springbootssm.model
# Mybatis mapper.xml映射文件配置
mapper-locations:
- classpath:mappers/*.xml
user-controller
可以看到UserController中的所有方法,然后点开逐一测试即可docker远程操控默认的端口是2375,但docker并未暴露此端口,2375可以在相对安全的内部网络中方便测试使用,并不适合使用在投入到生产环境中, 通过这个端口可以直接对远程的docker daemon进行操作。
docker官网第一篇文档quick start上有句话是这样子的:
Warning: Changing the default docker daemon binding to a TCP port or Unix docker user group will increase your security risks by allowing non-root users to gain root access on the host. Make sure you control access to docker. If you are binding to a TCP port, anyone with access to that port has full Docker access; so it is not advisable on an open network. 警告:将默认docker守护进程绑定更改为TCP端口或Unix docker用户组将增加安全风险,因为允许非root用户在主机上获得root访问权。确保控制对docker的访问。如果您绑定到TCP端口,任何访问该端口的人都可以完全访问Docker;因此在开放网络上不建议这样做。
/usr/lib/systemd/system/docker.service
文件# 1. 查看
cat /usr/lib/systemd/system/docker.service
# 2. 编辑
vim /usr/lib/systemd/system/docker.service
# 3. 找到ExecStart这一行
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
# 4. 添加端口,在3的最后追加 '-H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock'
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock
# docker.service文件修改后,执行命令systemctl restart docker 重启
[root@MiWiFi-R4CM-srv ~]# systemctl restart docker
Warning: docker.service changed on disk. Run 'systemctl daemon-reload' to reload
# 重启后提示run 'systemctl daemon-reload',意思是重新加载docker的守护进程
[root@MiWiFi-R4CM-srv ~]# systemctl daemon-reload
# 守护进程加载后再重启下docker
[root@MiWiFi-R4CM-srv ~]# systemctl restart docker
[root@MiWiFi-R4CM-srv ~]# docker pull java
打包成docker镜像的命令
clean package docker:build
:此命令会直接打包成tag为latest的docker镜像clean package docker:build -DpushImageTag
:此命令会打包成指定tag的docker镜像,可同时指定多个tag,详见pom.xml文件中的plugin配置
注意:点击上图的Execute按钮后,可能在控制台中输出 connect timed out 错误,此问题出现的原因是Centos防火墙未关闭造成的,具体内容如下
[ERROR] Failed to execute goal com.spotify:docker-maven-plugin:1.2.0:build (default-cli) on project springboot-ssm: Exception caught: Timeout: GET http://192.168.31.176:2375/version: com.spotify.docker.client.shaded.javax.ws.rs.ProcessingException: com.spotify.docker.client.shaded.org.apache.http.conn.ConnectTimeoutException: Connect to 192.168.31.176:2375 [/192.168.31.176] failed: connect timed out -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
[INFO] Copying G:\ideaProjects\springboot-ssm\target\springboot-ssm-0.0.1-SNAPSHOT.jar -> G:\ideaProjects\springboot-ssm\target\docker\springboot-ssm-0.0.1-SNAPSHOT.jar
[INFO] Building image spring-boot-ssm
Step 1/3 : FROM java
---> d23bdf5b1b1b
Step 2/3 : ADD /springboot-ssm-0.0.1-SNAPSHOT.jar //
---> 923ae6d7c2e8
Step 3/3 : ENTRYPOINT ["java", "-jar", "/springboot-ssm-0.0.1-SNAPSHOT.jar"]
---> Running in 6af726fff0e7
Removing intermediate container 6af726fff0e7
---> fc84ee54a42f
ProgressMessage{id=null, status=null, stream=null, error=null, progress=null, progressDetail=null}
Successfully built fc84ee54a42f
Successfully tagged spring-boot-ssm:latest
[INFO] Built spring-boot-ssm
[INFO] Tagging spring-boot-ssm with 0.0.1-SNAPSHOT
[INFO] Tagging spring-boot-ssm with 1.0
[INFO] Tagging spring-boot-ssm with latest
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 20.562 s
[INFO] Finished at: 2019-04-14T23:30:56+08:00
[INFO] ------------------------------------------------------------------------
Process finished with exit code 0
spring-boot-ssm
已被打包为docker镜像,如下所示:[root@MiWiFi-R4CM-srv ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
spring-boot-ssm latest 3a6f0b1dc90b 4 seconds ago 675MB
mysql 5.7.25 ee7cbd482336 5 weeks ago 372MB
java latest d23bdf5b1b1b 2 years ago 643MB
[root@MiWiFi-R4CM-srv ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
spring-boot-ssm latest 3982430be987 51 seconds ago 675MB
<none> <none> 06311fe4f5ab 13 minutes ago 675MB
spring-boot-ssm镜像
[root@MiWiFi-R4CM-srv ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
spring-boot-ssm latest 3a6f0b1dc90b 11 hours ago 675MB
mysql 5.7.25 ee7cbd482336 5 weeks ago 372MB
java latest d23bdf5b1b1b 2 years ago 643MB
IMAGE ID
在docker中启动一个名称为sbssm
的容器,如下[root@MiWiFi-R4CM-srv ~]# docker run -d --name sbssm -p 8080:8080 3a6f0b1dc90b
b509dde9b3eefde826659272ca1412b3afbad94c27b0024870f612d3e5df14ff
[root@MiWiFi-R4CM-srv ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b509dde9b3ee 3a6f0b1dc90b "java -jar /springbo…" 15 minutes ago Up 15 minutes 0.0.0.0:8080->8080/tcp sbssm
7092a3168b5f mysql:5.7.25 "docker-entrypoint.s…" 4 weeks ago Up 2 hours 0.0.0.0:3306->3306/tcp, 33060/tcp mysql