博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
springboot入门
阅读量:4103 次
发布时间:2019-05-25

本文共 13505 字,大约阅读时间需要 45 分钟。

前言

本文的主要内容:

事务处理

Docker安装及常用命令
接入Redis缓存及配置Session
整合MongoDB
配置开发与生产环境
部署项目到Docker上
事务处理

关于事务,可以简单理解为,当执行多条数据操作时,能确保每条操作能同时执行成功,否则有一条失败就会回滚前面所有执行成功的操作,保证一致性。下面我们来做一个简单的例子。

@Service

public class MyUserServices {
@Resource
private MyUserMapper userMapper;
@Transactional(rollbackFor = IllegalArgumentException.class, noRollbackFor = IllegalStateException.class)
public MyUser insertUser(MyUser user) {
userMapper.insertUser(user);
if (userMapper.selectUserByName2(user.getUserName()).size() >= 2) {
throw new IllegalArgumentException(“userName " +user.getUserName() + " is all through exist”);
}
if (user.getPassword().equals(“123456”)) {
throw new IllegalStateException(“can’t insert password 123456”);
}
return user;
}
}
可以看到我们给 inserUser方法添加了 Transactional注解,里面包含了 rollbackFor和 noRollbackFor两个属性,通过字面上我们可以看出,一个是回滚一个是不回滚,value值都是接收异常class。可以这样理解,当方法中抛出 rollbackFor定义的异常则会执行事务回滚,当方法中抛出 noRollbackFor定义的异常则不会执行事务回滚。后面有两个判断,一个是通过判断如果插入了两个相同的用户名,则抛出异常进行回滚,实际上开发中不会这样去做,这里是为了学习事务处理来做的,另一个是通过判断密码为123456抛出异常但不进行回滚。

Docker安装及常用命令

Docker是一个开源的应用容器引擎,基于Go语言并遵从Apache2.0协议开源。可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似iPhone的app),更重要的是容器性能开销极低。

安装完之后,运行下面命令,验证是否安装成功

docker version 或者docker info常用的docker命令如下: 搜索imagedocker search [imageNmae] 拉取 imagedocker pull [imageName] 列出本机所有 imagedocker image lsdocker images 查看 image 信息docker images [imageName] 强制删除 imagedocker rmi -f [imageId] 后台运行容器docker run -d [imageName] 查看正在运行的容器docker ps 杀掉容器docker kill [containerId]#在运行的容器中执行命令docker exec -it [containerId] [cmd]#强制删除容器docker rm -f [containerId]

接入Redis缓存及配置Session

通过Docker添加Redis, 两行命令完成, pull命令时间可能会比较久,需要耐心等待。

#拉取redis镜像文件

docker pull redis
运行redis容器
-p 6379:6379: 将容器的6379端口映射到主机的6379端口
-v $PWD/data:/data: 将主机中当前目录下的data挂载到容器的/data
-d redis redis-server --appendonly yes: 在容器中后台执行redis-server启动命令,并打开redis持久化配置
docker run -p 6379:6379 -v $PWD/data:/data -d redis redis-server --appendonly yes
接下来添加Redis依赖

org.springframework.boot
spring-boot-starter-data-redis
配置application.yml, 添加spring cache和redis配置, 密码默认为空:spring: cache: type: redis cache-names: soaic redis: database: 0 host: 192.168.0.184 port: 6379 password: jedis: pool: #连接池支持的最大连接数 max-active: 1000 #连接池中连接用完时,新的请求等待时间,毫秒 max-wait: -1ms #连接池中最多可空闲maxIdle个连接 max-idle: 400 min-idle: 0 timeout: 1000msMyUserServices核心代码:@Servicepublic class MyUserServices { @Resource private MyUserMapper userMapper; @CachePut(value = "user", key = "#user.id") //如果方法参数为对象,并且不指定key,需要重写toString方法 @Transactional(rollbackFor = IllegalArgumentException.class, noRollbackFor = IllegalStateException.class) public MyUser insertUser(MyUser user) { userMapper.insertUser(user); System.out.println("添加缓存key为"+user.getId()); if (userMapper.selectUserByName2(user.getUserName()).size() >= 2) { throw new IllegalArgumentException("userName " +user.getUserName() + " is all through exist"); } if (user.getPassword().equals("123456")) { throw new IllegalStateException("can't insert password 123456"); } return user; } @Cacheable(value = "user", key="id", condition="#id>0") //不指定key,默认以方法参数为key public MyUser selectUser(Integer id) { MyUser user = userMapper.selectUser(id); System.out.println("添加缓存key为" + id); return user; } @CacheEvict(value = "user") public Integer removeUser(Integer id) { Integer result = userMapper.deleteUser(id); System.out.println("删除缓存key为" + id); return result; }}

注解 @CachePut()表示当有缓存刷新缓存,没有则添加缓存,有三个属性, value为缓存的名称为application.yml配置的cache-names; key为缓存的key, 如果不指定key,默认以方法参数为key,如果方法参数为对象,需要重写toString方法; condition为缓存的条件,条件为true时才进行缓存。注解 @Cacheable()表示当有缓存则取缓存,没有则添加缓存,三个属性和注解@CachePut()属性一致。注解 @CacheEvict()表示当有缓存则清除缓存,除了前面说的三个属性外,还多出两个属性, allEntries为true清除所有元素;beforeInvocation为true时表示在调用该方法之前清除缓存中的指定元素,默认是方法成功执行之后触发,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。

SpringBoot 入门

接着添加RedisCacheConfig配置key生成规则、配置RedisTemplate和缓存序列化以json格式存储

@Configuration@EnableCachingpublic class RedisCacheConfig extends CachingConfigurerSupport { /** * 配置redis key */ @Bean @Override public KeyGenerator keyGenerator() { return (target, method, params) -> { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); for (Object obj : params) { sb.append(":"); sb.append(obj.toString()); } return sb.toString(); }; } /** * RedisTemplate 序列化 */ @Bean public RedisTemplate
redisTemplate(RedisConnectionFactory redisConnectionFactory) { Jackson2JsonRedisSerializer redisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); redisSerializer.setObjectMapper(objectMapper); RedisTemplate
redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setValueSerializer(redisSerializer); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } /** * redis 缓存序列化 */ @Bean public CacheManager cacheManager(RedisConnectionFactory connectionFactory){ Jackson2JsonRedisSerializer
redisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); redisSerializer.setObjectMapper(objectMapper); RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)); return RedisCacheManager.builder(connectionFactory).cacheDefaults(cacheConfiguration).build(); }}

最后把 MyUser实现 Serializable, 否则会报序列化错误

public class MyUser implements Serializable {

}
测试。先通过Controller(这里没有写出代码,可以到github上查看)调用MyUserServices中方法,然后进入docker运行的容器查看

查看正在运行的容器ID

docker ps
#进入redis容器中
docker exec -it [containerId] redis-cli
进入之后输入 info 可以查看redis信息
info
查看所有key
keys *
查看某个key的值
get key
接下来就是配置Session了。为什么要用redis配置session?有这么几点原因:1、方便管理session 2、托管到redis共享Session方便使用集群, 即一台服务器坏了,切换到另一台服务器,无需再次登录还能正常访问

首先添加依赖

org.springframework.session
spring-session-data-redis

要注意一下的是,如果 spring-boot-starter-parent版本是2.1.5.RELEASE时,添加依赖后运行会报下面这个错误,解决办法可以把版本降低,改成2.1.4.RELEASE即可。

java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration.taskScheduler

配置application.yml, 设置session存储方式

spring: session: store-type: redis添加RedisSessionConfig配置,启用Session, 并设置失效时间@Configuration@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)//原 Spring Boot 的 server.session.timeout 属性不再生效。public class RedisSessionConfig {}

接下来配置Session拦截器以及Login接口中登录成功设置session,上篇文章中介绍的还比较详细,这里就简单的贴一下核心代码:

SessionInterceptor核心代码@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("SessionInterceptor preHandle"); HttpSession session = request.getSession(false); if (session != null && session.getAttribute("user") != null) { return true; } else { PrintWriter printWriter = response.getWriter(); printWriter.write("{code: 501, message:\"not login!\"}"); return false; }}MyUserController核心代码@RequestMapping(value = "/login", method = RequestMethod.GET)public ResponseResult
login(HttpServletRequest request, String userName, String password) { ResponseResult
responseResult; try { List
myUser = myUserServices.login(userName, password); if (myUser != null && myUser.size() > 0) { request.getSession(true).setAttribute("user", myUser.get(0)); responseResult = new ResponseResult<>(200, "login success", myUser.get(0)); } else { responseResult = new ResponseResult<>(501, "login failure: invalid userName or password", null); } } catch (Exception e) { e.printStackTrace(); responseResult = new ResponseResult<>(501, "login failure: " + e.getMessage(), null); } return responseResult;}

最后测试,当第一时间访问其它接口会报501错误,而当访问login登录成功后,则会保存session,后面其它接口访问都可以正常。这里没有用多台服务器测试,只测试了下,当服务器停止再启动后,访问接口都不用再重新登录,session存储在redis中,不会因为服务器断开而消失,这就区别于不托管redis,session是存储在内存中,每次停止服务器再启动都要重新登录。

整合MongoDB

通过Docker添加MongoDB, 同样两行命令完成。

docker pull mongo

-p 27017:27017: 将容器的27017 端口映射到主机的27017 端口
-v $PWD/db:/data/db: 将主机中当前目录下的db挂载到容器的/data/db,作为mongo数据存储目录
docker run -p 27017:27017 -v $PWD/db:/data/db -d mongo
添加MongoDB依赖

org.springframework.boot
spring-boot-starter-data-mongodb
配置application.yml, 这里用Docker添加的所以没有账号密码,当有账号密码时,url格式为:mongodb://user:pwd@ip:port/soaic?maxPoolSize=256; 当有多台数据库时,url格式为:mongodb://user:pwd@ip1:port1,ip2:port2/database?maxPoolSize=512spring: data: mongodb: uri: mongodb://localhost:27017/soaic?maxPoolSize=256

修改MyUser对象, 在类作用域上添加 @Document注解定义为一个文档,,也可以理解为是一张表,注解 @Id定义属性为ID, 注解 @Field定义为存储表中的字段名

@Document("myUser")public class MyUser implements Serializable { @Id private String id; private String userName; private String password; @Field("roles") //在文档中的名称为roles, 以数组形式存储 private Collection
roles = new LinkedHashSet<>();}添加 Role 对象public class Role { private String roleName; public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; }}

在SpringBoot中对mongoDB操作数据有多种方式,如:通过继承 MongoRepository对象调用定义好的方法, 或者遵从定义方法名的规则,或者通过注解 @Query实现查询, ?0为占位符取方法参数的第一个,依次类推

public interface MyUserRepository extends MongoRepository
{ List
findByUserName(String name); @Query("{'userName': ?0}") List
withQueryUserName(String name);}

通过 MongoTemplate来实现, 下面代码简单的实现了增删改查CRUD

@Service public class MyUserDaoImpl implements MyUserDAO{ @Autowired MongoTemplate mongoTemplate; @Override public List
findByUserName(String userName) { Query query = new Query(Criteria.where("userName").is(userName)); return mongoTemplate.find(query, MyUser.class); } @Override public MyUser insertUser(MyUser myUser) { return mongoTemplate.insert(myUser); } @Override public boolean deleteUser(String id) { Query query = new Query(Criteria.where("id").is(id)); DeleteResult result = mongoTemplate.remove(query, MyUser.class); return result.getDeletedCount() > 0; } @Override public boolean updateUser(MyUser myUser) { Criteria criteria= Criteria.where("id").is(myUser.getId()); Update update = new Update(); if (myUser.getUserName() != null) update.set("userName", myUser.getUserName()); if (myUser.getPassword() != null) update.set("password", myUser.getPassword()); UpdateResult result = mongoTemplate.updateFirst(new Query(criteria), update, MyUser.class); return result.getModifiedCount() > 0; }}

通过单元测试对上面的代码进行测试, 在test/java/com.soaic.hellospringboot中创建MongoDBTests, 添加注解 @SpringBootTest和 @RunWith(SpringRunner.class), 测试的方法添加 @Test注解,然后分别点击方法左边的绿色小图标 Run Test 即可

@RunWith(SpringRunner.class)@SpringBootTestpublic class MongoDBTests { @Autowired private MyUserRepository myUserRepository; @Autowired private MyUserDaoImpl myUserDaoImpl; @Test public void testSave() { MyUser myUser = new MyUser(); myUser.setUserName("Soaic"); myUser.setPassword("123456"); Collection
roles = new LinkedHashSet<>(); Role role = new Role(); role.setRoleName("管理员"); roles.add(role); Role role1 = new Role(); role1.setRoleName("程序员"); roles.add(role1); myUser.setRoles(roles); //myUserRepository.save(myUser); myUserDaoImpl.insertUser(myUser); } @Test public void testFind() { List
myUserList = myUserDaoImpl.findByUserName("Soaic"); System.out.println(JSON.toJSONString(myUserList)); } @Test public void testUpdate() { List
myUserList = myUserRepository.withQueryUserName("Soaic"); for (MyUser myUser: myUserList) { myUser.setPassword("1234567"); myUserDaoImpl.updateUser(myUser); } } @Test public void testDel() { List
myUserList = myUserRepository.findByUserName("Soaic"); for (MyUser myUser: myUserList) { myUserDaoImpl.deleteUser(myUser.getId()); } }}

查询mongoDB数据库数据有无变化,可以通过如下命令连接mongoDB查询

连接mongodb

docker run -it mongo mongo --host 172.17.0.1

查看所有数据库

show dbs

切换数据库

use soaic

查看数据库状态

db.stats()

查询数据库下所有表

show collections

查询某个表的数据

db.collection.find()

配置开发与生产环境

添加 application-dev.yml开发环境配置和 application-prod.yml生产环境配置, 如果我们想使用生产环境,因为程序会默认加载 application.yml, 所以只需要在里面配置 spring.profiles.active为 prod即可,配置为 dev则为开发环境。

spring:

profiles:
active: prod
部署项目到Docker上

部署到Docker上需要先把项目打包成jar包,可以通过idea中的 Maven Projects 找到Lifecycle下的clean 和 package 依次双击执行(也可以执行命令 mvn cleanpackage),最后就可以在target文件夹下找到 hellospringboot-0.0.1-SNAPSHOT.jar

如果不部署到Docker上,可以直接运行下面命令启动项目

java -jar hellospringboot-0.0.1-SNAPSHOT.jar

如果部署到docker上,我们需要创建一个Dockerfile文件在项目的根目录,里面内容如下:

FROM java:8

MAINTAINER Soaic
ADD target/hellospringboot-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8443
EXPOSE 8088
ENTRYPOINT [“java”, “-jar”, “/app.jar”]
第一行:基于镜像为Java, 标签版本为8 第二行:作者Soaic 第三行:将hellospringboot-0.0.1-SNAPSHOT.jar添加到镜像中,并重命名为app.jar 第四行和第五行:运行镜像的容器,监听8443和8088端口 第六行:启动时运行 java -jar app.jar

接下来编译镜像,在项目根目录下执行下面命令,其中hellospringboot为镜像名称,最后一个".",用来指明Dockerfile路径,表示在当前路路径下,编译第一次需要下载java8,后面编译就不需要下载了

docker build -t hellospringboot .

编译完成后,可以通过下面命令查看及运行项目

查看是否有一个image为hellospringboot

docker images

后台运行项目,并映射两个端口号8443和8088,–name为修改运行容器名称可加可不加默认为image名称

docker run -d --name hellospringboot -p 8443:8443 -p 8088:8088 hellospringboot

最后可以通过 和 这个两个地址访问了。

彩蛋时间:免费分享Java技术资料,需要的可以私信我

在这里插入图片描述
SpringBoot 入门
来源:知乎

作者:白天不懂夜的黑

原文:

转载地址:http://ndusi.baihongyu.com/

你可能感兴趣的文章
Linux 设备驱动框架
查看>>
使用busybox
查看>>
platform_device与platform_driver
查看>>
android平台6410背光修改
查看>>
Uboot之一:BootLoader的概念
查看>>
6410平台500W摄像头调试过程 && 拍照偏绿和图片保存等BUG
查看>>
linux的触摸屏之一:原理及APK调试
查看>>
python 正则表达式
查看>>
ubuntu基本操作 - ssh的使用
查看>>
Linux脚本(shell)编程(一) 简单入门HelloWorld
查看>>
Linux脚本(shell)编程(二) 基本语法
查看>>
射频模块的作用
查看>>
手机射频
查看>>
android的system.img,userdata.img,ramdisk.img分析
查看>>
android root 权限分析
查看>>
android平台下lcd调试流程
查看>>
android系统开发 AP 和 BP 简要说明
查看>>
关于GSM的频段
查看>>
Android软件测试的日志文件抓取简介
查看>>
Android ANR错误排查
查看>>