A01 Spring Boot企业微信点餐系统.txt
UP 返回
地址:E:\2019年4月黑马程序员教程\03-Java慕课网项目实战\02-Spring Boot实战(共6套)\02-某客网Spring Boot企业微信点餐系统
项目:D:\ProjectCodes\learning_pro\sell
项目的sql等资料参原工程文件:E:\2019年4月黑马程序员教程\03-Java慕课网项目实战\02-Spring Boot实战(共6套)\02-某客网Spring Boot企业微信点餐系统\r1l5jr
此教程中工程文件内容很少
【注意】以下关于网址的记录可能会发生变化,以实际操作为准
项目开始时没有找到源代码,所以手敲了部分代码,在工程sell_editmyself中;后续找到了全部代码,重新使用了sell工程。sell里面使用的微信SDK还是很老的版本,sell_editmyself是当前较新的,以后如果要用可以适应新的版本
且最开始的虚拟机在中途出现了问题,后面重新部署了,所以3.1以及以前的代码和截图可能和sell及新虚拟机中有出入,和sell_editmyself中保持一致。后续笔记都以sell为准
1. 环境准备
1.1 模型设计
表结构:
!!@@202209203.png_1420_672_1@@!!
建表语句中,针对current_timestamp的使用,为update_time开启了事件,即在发生更新语句时自动更新为当前时间
而此功能在mysql5.7(或者5.6,没细究)以下时,所有语句只允许有一个默认的current_timestamp,包括默认值和on update事件值。而本地数据版本为5.5无法执行,故所有SQL都将update_time的默认去掉了
`update_time` timestamp not null default current_timestamp on update current_timestamp comment '修改时间',
改为:`update_time` timestamp comment '修改时间',
!!@@202209202.png_924_152_1@@!!
1.2 虚拟机
使用virtualBox导入虚拟机(教程目录下的 \centos7.3.ova),导入时注意选择 为所有网卡重新生成mac地址。导入后打开即可,虚拟机已经安装好了需要的环境,参数见r1l5jr目录下的VM.md
账号密码:root 123456
!!@@202209205.png_709_201_1@@!! !!@@202209204.png_754_165_1@@!!
当前ip地址为192.168.1.104(虚拟机后面出了问题,重新部署了一台centos7.3_1 1。休眠电脑貌似会破坏虚拟机,尽量少用),要确保和主机电脑在一个网段,两边互相是可以ping的,如果不行可以采用下面的设置后重启,具体选哪个网卡不知道,因为暂时没出现这种情况(参视频 \第03章 项目起步\3-1 开发环境搭建.wmv)
!!@@202209206.png_957_557_1@@!!
连接虚拟机的数据库,创建库sell,注意选择字符集utf8mb4,这种是可以存储表情的,单纯的utf8会报错。这里可以直接执行给的SQL语句,因为虚拟机的版本是够的
!!@@202209208.png_440_198_1@@!!
1.3 项目日志配置
!!@@202209211.png_1006_708_0.5@@!!
日志门面使用slf4j,日志实现使用logback。
使用lombok的@Slf4j注解可以自动为当前类提供一个log变量直接使用。LoggerFactory.getLogger中给定的class将在日志输出时显示,帮助定位
!!@@202209213.png_1179_821_1@@!!
1.3.1 使用springboot的配置文件来配置日志: application.yml
logging:
pattern:
console: "%d - %msg%n" 日志格式
path: /var/log/tomcat 指定日志的目录,默认的日志文件名为spring.log。在本机上地址就是D:\var\log\tomcat\spring.log
file: /var/log/tomcat/sell.log 指定日志名,如果配置了这个上面那个就不用了
level:
com.imooc.dataobject.ProductCategory: debug 日志级别可以指定到具体的类。level也可以直接给debug,视频可以但是本地爆红了
1.3.2 使用logback自带的配置文件: logback-spring.xml
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!--控制台的日志配置-->
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>
%d - %msg%n
</pattern>
</layout>
</appender>
<!--info日志 采用每天生成一个文件-->
<appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--设置info的日志里只打印info级别的信息 如果使用后面error的那种配置,因为error级别比info高,所以还是会全部打印-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch><!--匹配到error级别的日志则拒绝-->
<onMismatch>ACCEPT</onMismatch><!--否则才打印,这样就不会在info中打印error了-->
</filter>
<encoder>
<pattern>
%msg%n
</pattern>
</encoder>
<!--滚动策略 一天一个文件-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--路径-->
<fileNamePattern>/var/log/tomcat/sell/info.%d.log</fileNamePattern>
</rollingPolicy>
</appender>
<appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--设置error的日志里只打印error级别的信息-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<encoder>
<pattern>
%msg%n
</pattern>
</encoder>
<!--滚动策略 一天一个文件-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--路径-->
<fileNamePattern>/var/log/tomcat/sell/error.%d.log</fileNamePattern>
</rollingPolicy>
</appender>
<root level="info">
<appender-ref ref="consoleLog" />
<appender-ref ref="fileInfoLog" />
<appender-ref ref="fileErrorLog" />
</root>
</configuration>
1.3.3 springboot默认的日志配置如下:
!!@@202209271.png_1854_758_1@@!!
2. 代码开发
2.1 商品开发(04 05章节)
ProductCategory 商品类目 product_category
ProductInfo 商品 product_info
修改虚拟机的nginx后台请求地址,使数据从本机请求:
vim /usr/local/nginx/conf/nginx.conf
nginx -s reload
!!@@202209281.png_694_499_1@@!!
访问前端地址:(虚拟机已经自带前台的代码了) ▶这里有一个修改cookie的技巧,参笔记
http://192.168.1.104/#/
!!@@202209282.png_1448_714_1@@!!
修改虚拟机的地址,使用域名来访问,修改后重启一下nginx(这里修改的是虚拟机的,与本地的无关;所以下面修改本地还是要改host的):
!!@@202209285.png_661_446_1@@!!
修改本机的host
!!@@202209288.png_607_246_1@@!!
重新访问http://sell.com/#/效果相同(可能需要重新加一下cookie:document.cookie='openid=123abc')
2.2 买家订单开发(06章节)
OrderMaster 订单主表 order_master
OrderDetail 订单字表,和商品关联 order_detail
在订单列表方法中,涉及到时间需要取秒值,而后台给的是毫秒值,这是可以使用@JsonSerialize注解来指定格式序列化(依赖于springboot自动引入的fasterxml.jackson):
首先创建格式化序列化的类,需要继承JsonSerializer,重写serialize方法,在这里完成实际的转换(比如这里对毫秒取秒数)
!!@@202210051.png_1609_193_1@@!! 泛型中指定了类为日期类JsonSerializer<Date>
在需要格式化的字段上加上@JsonSerialize,并指定序列化的类是刚刚创建的类。这样传到前端的时间格式就是秒数了:
!!@@202210052.png_897_215_1@@!!
有时候希望模型中字段如果是null就不要传给前端,可以使用注解@JsonInclude(JsonInclude.Include.NON_NULL);如果希望字段为null就给个初始化的值,可以在dto中给对应字段初始化一个默认值即可
!!@@202210053.png_1362_235_1@@!!
上面的注解只对给了的类有效,如果希望在整个项目里都是这样处理,可以直接在配置文件中指明
!!@@202210054.png_1091_310_1@@!!
2.3 微信支付 ▶以下参下面的第3节
2.4 卖家订单开发 【09章】
使用 http://www.ibootstrap.cn/ 拖拽生成前端页面模板(商家页面使用freemarker)
!!@@2022101613.png_1401_662_1@@!! !!@@2022101614.png_1539_759_1@@!!
需要引入css : <link href="https://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
页面布局如下:
!!@@2022101621.png_1022_586_1@@!!
这里有一个获取枚举信息的设计,这样设计可以避免为了获取枚举的message需要在每一个枚举类中都写一次遍历的逻辑:
首先把需要显示到前端的枚举类继承接口CodeEnum,接口中定义方法getCode,这里要求这些枚举中都要有一个int型的code
!!@@2022101616.png_634_247_1@@!!
然后定义一个枚举工具类,在这里通过泛型根据code获取对应的枚举值
!!@@2022101617.png_1131_290_1@@!!
在对应的DTO中添加获取枚举对象的方法,这里要在方法上加上@JsonIgnore,不然后面转成的json中也会带一个getOrderStatusEnum的字段
!!@@2022101618.png_1259_240_1@@!!
在前端,我们使用这个get方法来获取枚举的具体信息:orderDTO.getOrderStatusEnum().message
!!@@2022101619.png_1213_341_1@@!!
卖家订单地址 http://hongwen.nat300.top/sell/seller/order/list 提供列表查询 详情和取消订单的功能;订单详情中可以完结和取消订单
2.5 卖家商品 【10章】
页面在product,提供商品列表 上下架 新增和编辑的功能
商品类目 【11章】
页面在category,提供列表 编辑的功能
2.6 登录 【12章】
商家可以通过微信扫码登录自己的后台管理页面,使用微信的开放平台,与之前支付的平台不同。这个平台必须是公司的资质才可以申请到登录的功能,不像之前的支付功能,代码中的配置为openAppId openAppSecret,对应配置类为WechatAccountConfig WechatOpenConfig
参考文档:https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
!!@@202210231.png_1698_700_1@@!!
登录的过程如下:
首先浏览器会检查cookie里有没有openid,如果没有,就会访问 sell.natapp4.cc/sell/wechat/qrAuthorize?returnUrl=http://sell.natapp4.cc/sell/seller/login 在后台可以看到这个接口(WechatController类)会调用微信的地址,弹出扫码界面,扫码成功后重定向到获取用户信息的接口/qrUserInfo
在获取用户信息的接口中微信会把用户信息和上一步的重定向地址returnUrl=http://sell.natapp4.cc/sell/seller/login 带过来,后台可以从用户信息中获得openid,这样就把openid拼到returnUrl后面,继续重定向到登录接口/sell/seller/login
在商家登录接口(SellerUserController)中,根据openid去表seller_info中查询对应的用户,如果存在,就设置token的openid并存入redis,最后重定向到订单页面 /sell/seller/order/list
return ModelAndView中重定向的url尽量使用绝对地址,使用相对的地址可能拼接出的网址不是自己需要的:return new ModelAndView("redirect:" + projectUrlConfig.getSell() + "/sell/seller/order/list");
退出登录时清除掉cookie里的openid和redis中的key即可
【现在的登录路径是 http://hongwen.nat300.top/sell/seller/login?openid=11111 这个openid和库中商家信息一致。本身微信扫码最后也是获取openid跳到这个链接上,后台就会在token中存入
对于商家的页面(SellerProductController SellerOrderController SellerCategoryController),我们希望必须登录以后才可以访问,使用aop的方式创建切面SellerAuthorizeAspect,在这里检查token和openid,如果不符合则抛出SellerAuthorizeException异常
!!@@202210241.png_1393_734_1@@!! 相关的注解 @Aspect @Pointcut @Before
创建异常处理类SellExceptionHandler,专门接收SellerAuthorizeException异常,当出现这种异常时说明用户openid没有,就重定向到微信的扫码登录接口,也就是上面登录过程的第一步
!!@@202210242.png_1137_410_1@@!! 相关的注解 @ControllerAdvice @ExceptionHandler(value = SellerAuthorizeException.class)
商家可以通过微信给下单用户的微信推送订单消息,后台实现为PushMessageServiceImpl,调用SDK即可(具体的调用过程可以参考微信文档)。当订单完结时(由商家在管理页面点击)调用该推送方法,提醒用户收货
!!@@202210243.png_1170_490_1@@!!
使用websocket,当有新订单出现时在商家的订单页面可以自动弹出消息框并播放音乐
前台页面的写法:!!@@202210244.png_1744_802_1@@!! !!@@202210246.png_1276_772_1@@!!
后台长链接写法(类在WebSocket):!!@@202210247.png_1271_817_1@@!!
在订单创建流程中调用WebSocket的sendMessage方法,向页面发送消息。可以通过postman调用订单生成接口测试
3. 微信支付【07 08章】
个人是无法申请微信支付,必须是企业,即普通商户;服务商可以理解为微信代理商
必须是服务号才可以开通支付功能,普通的订阅号没有,当前并没有注册,以下操作均是假定已有服务号的基础
相关链接:
官方文档 https://pay.weixin.qq.com/wiki/doc/api/index.html
!!@@202210062.png_903_919_1@@!!
调试 https://natapp.cn
第三方SDK https://github.com/Wechat-Group/weixin-java-tools
3.1 获取openid 【07章】
文档地址:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
在公众号的设置中可以添加关联的域名:
!!@@202210063.png_1264_665_1@@!! !!@@202210064.png_1269_726_1@@!!
使用natapp开启内网穿透,使外网可以访问自己的电脑。注意保证域名是可以支持微信开发的,也可以关联自己的域名
!!@@202210066.png_1888_783_1@@!!
穿透好以后,按照公众号的要求,我们把文件MP_verfy_ nNzSrJz2eqzbFly.txt下载后放入static目录,这个时候我们可以通过以下路径访问到文件
http://hongwen.nat300.top/sell/MP_verfy_%20nNzSrJz2eqzbFly.txt ▶http://hongwen.nat300.top 是目前的测试域名,这个域名是无法开发微信的,以后可以使用www.wholewen.top
但是微信必须要求在根路径访问到才能关联到域名,所以要先把配置的sell前缀删掉,确保最后是以下路径可以访问,就可以关联成功了。关联成功以后这个文件就可以删了,同时sell的前缀也可以恢复回来
http://hongwen.nat300.top/MP_verfy_%20nNzSrJz2eqzbFly.txt
按照文档的说法,我们需要引导用户打开如下链接
!!@@202210069.png_1047_224_1@@!!
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxd898fcb01713c658&redirect_ uri=http://sell.natapp4.cc/sell/weixin/auth&response_ type= code&scope=snsapi_base&state=123#wechat_redirect
上述的appid与小程序对应,redirect_ uri将被微信回调,那么我们就要在项目中开出/weixin/auth的接口以供回调(参WeixinController)。回调的时候会传入code,我们通过这个code获取access_token
!!@@2022100610.png_822_145_1@@!!
特别的,在获取code的时候,这种获取方式会直接回调,用户是无感知的,当然获取到的信息就比较少;如果将scope换成snsapi_userinfo,就可以拿到用户的一些基本信息,但是需要用户点击同意授权框(参微信文档)
使用第三方sdk,参上述github地址,引入公众号依赖。参WechatController
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>4.4.0</version>
</dependency>
修改前端地址配置,使其能够定向到后台接口:
进入前台项目的配置文件夹 /opt/code/sell_fe_buyer/config 修改index.js。
!!@@202210071.png_890_172_1@@!!
然后回到上层目录重新构建项目 npm run build
构建好的项目的dist目录下,将该目录下的文件全部复制覆盖到网站根目录下(nginx无需重启)
!!@@202210073.png_1003_528_1@@!!
这个时候从前台页面上就可以跳到请在微信打开的页面
但是如果用手机访问sell.com,肯定是到不了后台的。虚拟机上可以是因为之前配置过nginx的地址。这里需要使用手机wifi代理,同时使用抓包工具,mac上是Charles,windows是fiddler
可以看到手机的ip是192.168.1.100,电脑是可以ping通的
我们需要修改手机的wifi,配置代理,选择手动,服务器为电脑地址192.168.1.106,端口8888,保存,这样以后手机的请求都会转到电脑上(注意目前发现这样设置以后有的app无法访问,以后再深入研究)
3.2 微信支付 【08章】
视频使用的支付sdk是做着自己开源的best-pay,支持微信和支付宝:https://github.com/Pay-Group/best-pay-sdk
<dependency>
<groupId>cn.springboot</groupId>
<artifactId>best-pay-sdk</artifactId>
<version>1.1.0</version>
</dependency>
支付类为PayController,创建订单的api为/pay/create,这个接口需要传入订单id和返回url。订单id是用来在后台查询订单信息的,而返回url会填充到支付模板中,等用户支付完成后会返回到该页面
修改前端支付地址,使之访问的接口就是上面的订单创建api,重新build一下
!!@@202210163.png_687_433_1@@!!
注意我们需要配置支付的授权目录,以实际支付模板所在页面为准。比如我们项目的根路径是/sell,如果要直接访问支付页index.html,那么就要像下面这样把/sell/添加进去
!!@@202210165.png_1271_709_1@@!!
实际上我们的支付模板是pay目录下的create.ftl,所以下面那个/sell/pay才是真正后面要用的
这样,在前端选好商品以后点击支付,页面就会请求/pay/create,在该接口中向微信发起了支付申请,微信支付会返回时间戳 签名等参数,再将这些参数填充并重定向到支付模板pay/create.ftl中,前端就会跳入立即支付的页面
create.ftl是仿造pay.html改写的,pay.html是官方文档中给出的支付示例,微信访问这个就会显示出要求支付的页面
这里使用了freemarker技术,引入依赖即可使用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
!!@@202210166.png_793_506_1@@!! !!@@202210167.png_852_477_1@@!! !!@@202210168.png_996_670_0.5@@!!
代码逻辑如下:
PayController的/pay/create为订单创建入口,调用PayServiceImpl创建支付请求,在PayServiceImpl中引用了SDK的BestPayServiceImpl,我们在WechatPayConfig中定义了BestPayServiceImpl的创建方式,同时引入了支付各个参数的配置WechatAccountConfig
在application.yml中可以看到支付成功后异步通知的接口/sell/pay/notify
至此,用户支付完成以后即可跳到returnUrl。但是我们不能依赖页面的逻辑来判断是否支付成功,因为本身微信就说了不保证,其次也可能被篡改,所以在后面的/pay/notify中判断支付成功与否(此接口是由微信发起调用的)
在该请求中,需要严格校验,其中验证签名和支付状态已经由sdk完成,支付金额我们也需要重新校验保证和库里订单一致,支付人这里没有做校验,根据实际情况来
!!@@202210169.png_863_746_1@@!!
当订单状态修改完毕以后,我们需要给微信返回以下结果通知已经处理完毕,否则微信会一致调用上面的异步通知接口
!!@@2022101610.png_1163_589_1@@!!
微信退款:【08章 07集】
参照微信支付文档,配置证书,文档里有证书下载地址
!!@@2022101611.png_779_284_1@@!!
退款方法为refund,在之前取消订单的方法里调用退款就可以了
也可以使用测试账号开发,在08集有讲,这里不再折腾了,因为账号不是服务号,配置不了后面的支付操作,一直报错。。。。
4. 项目优化
4.1 异常的处理 【13章 13-1】
当出现异常时,抛出的结果并不是我们想要的异常格式:
!!@@202210248.png_833_715_1@@!!
所以创建一个专门处理SellException的方法,来重新包装异常类,返回给前端
但是即使处理了,返回的异常信息中http的code还是200;有时候我们希望针对异常返回其他的httpcode,可以使用注解@ResponseStatus指定
!!@@202210249.png_1152_344_1@@!! !!@@2022102410.png_886_666_1@@!!
4.2 mybatis的使用 【13章 13-2 - 13-5】
首先引入mybatis的依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
创建mapper包,在里面定义Mapper接口,SQL语句可以通过注解写在代码里,也可以写在xml里,xml文件一般放在resources/mapper下
!!@@202210261.png_1611_682_1@@!! !!@@202210262.png_1362_372_1@@!!
使用的时候一般会新建一个dao类,将mapper接口引入,再在dao类中创建对外的方法,对内调用mapper的这些语句
启动类上需要将mapper所在的包加入扫描路径,同时配置文件中需要指定mapper的位置
!!@@202210263.png_811_174_1@@!! !!@@202210264.png_836_190_1@@!!
如果想要日志打印SQL语句,可以如上配置mapper包下的日志打印级别
4.3 分布式锁 【13章 13-6 - 13-8】
对应秒杀类:SecKillController SecKillServiceImpl 秒杀方法是接收一个productId,然后上锁减库存
如果直接在秒杀方法上加synchronized,加锁粒度太粗,这样任何一个商品进秒杀都得等待(比如A商品很火爆而B没有,那B也要参与A的锁获取);同时这个方法只能适合单机版,不是分布式锁
这里使用redis实现分布式锁,代码在RedisLock:
!!@@202210302.png_1199_766_1@@!!
4.4 缓存 【13章 13-9 - 13-10】
springboot的web自动引入了spring-boot-starter-cache,这个就是缓存的注解依赖
启动类上需要添加 @EnableCaching 注解。返回页面的对象(比如那些VO类)需要实现序列化
我们在 BuyerProductController 的 list 方法上添加注解 @Cacheable(cacheNames = "product", key = "123") 这个查询就会用到缓存
但是当我们在商家页面修改了商品时,这个值还是取的缓存,没有发生修改
此时需要在 SellerProductController 的 save 方法上添加注解 @CachePut(cacheNames = "product", key = "123") 这样修改就会将这个方法返回的对象写入对应的缓存
但是保存后会报错,因为这个方法的返回值是ModelAndView,与查询方法需要的返回值不一致,而且ModelAndView是自带的也无法序列化
这个时候就要用注解 @CacheEvict(cacheNames = "product", key = "123") 这个修改执行完以后就会删除这个缓存,那么下次查询就会走库了
如果一定要使用@CachePut注解,一定要保证查询和修改的返回值一致且实现序列化。我们使用 ProductServiceImpl 的 findOne 和 save 方法可以看到效果(分别对应商品的编辑初始化和编辑保存操作)
cache的key如果不给,那么默认的就是方法的参数,所以一般最好指定
cache的cacheNames如果是一致的,可以再类上直接加注解 @CacheConfig(cacheNames = "product") 这样下面就只用给key了
@Cacheable 的key也可以是表达式,比如参数中有一个sellerId,那么就可以写成#sellerId;还可以加场景condition,这样只有满足的才会进缓存;还可以用unless指定入缓存的条件,unless成立的情况下将不入缓存,比如我们只想要正确的查询结果入,就可以用ResultVO的code来判断,其中#result代指返回对象
@Cacheable(cacheNames = "product", key = "#sellerId", condition = "#sellerId.length() > 3", unless = "#result.getCode() != 0")
public ResultVO list(String sellerId) { ... }
5.部署
5.1 Tomcat
5.2 java -jar
mvn clean package -Dmaven.test.skip=true 进入项目目录打包,跳过单元测试。打出的包在target下,sell-0.0.1-SNAPSHOT.jar。如果想指定包名,可以在pom的build中添加<finalName>sell</finalName>
将打的包放到服务器/usr/local/mysell/sell.jar,直接java -jar运行。如果端口占用可以指定端口启动:java -jar -Dserver.port=8090 sell.jar
访问 http://192.168.1.104:8090/sell/buyer/product/list 可以看到JSON信息,控制台也会打印SQL
如果我们想在开发环境打印SQL而生产环境不打印,可以使用指定环境。将配置文件复制一份分别命名为application-dev.yml application-prod.yml。删掉生产环境配置application-prod.yml中打印SQL的配置:show-sql: true
再创建一个配置文件application.yml,在这里指定配置文件为dev。本地启动可以看见还是会打印sql
spring:
profiles:
active: dev
重新打包放到虚拟机,启动时指定配置文件的环境为生产环境(注意参数要与配置文件中的参数前缀保持一致),再次访问上述链接时就不再打印sql了:
java -jar -Dserver.port=8090 -Dspring.profile.active=prod sell.jar
如果想要后台启动项目,可以使用如下命令,返回的是进程号:
nohup java -jar -Dserver.port=8090 sell.jar > /dev/null 2>&1 &
ps -ef |grep sell.jar 查看进程
可以创建一个启动脚本,将上面的命令复制进去
vim start.sh 文件内容如下:
#!/bin/sh
nohup java -jar -Dserver.port=8090 sell.jar > /dev/null 2>&1 &
!!@@202211011.png_560_74_1@@!!
使用 bash start.sh 启动即可(可以用上述查看进程的命令查看)
kill -9 2530 关闭进程,2530是ps -ef |grep sell.jar 查询到的进程号
centos7推荐使用service的方式运行进程:
cd /etc/systemd/system/ 进入该目录,可以ll一下看看有哪些文件
vim sell.service 为该项目创建一个文件,文件内容如下: ▶After表示启动sell服务的依赖,需要先启动另外两个服务;Type是启动类型;ExecStart是具体的启动命令
[Unit]
Description=sell
After=syslog.target network.target
[Service]
Type=simple
ExecStart=/usr/bin/java -jar -Dserver.port=8090 /usr/local/mysell/sell.jar
ExecStop=/bin/kill -15 $MAINPID
User=root
Group=root
[Install]
WantedBy=multi-user.target
systemctl start sell 启动服务。启动后可以查询到sell对应的进程(也可以写全名sell.service,不写也可以)
systemctl stop sell 停止服务。此时搜不到进程了
systemctl enable sell 开机启动
systemctl disable sell 停止开机启动
!!@@202211012.png_962_188_1@@!!
DOWN 返回