Java项目笔记之秒杀系统基础搭建

ε祈祈猫儿з 提交于 2021-01-03 11:45:51
不点蓝字,我们哪来故事?


秒杀系统

目的:不仅仅是秒杀!!!


项目搭建

基础模块搭建


创建仓库替换config配置中的仓库路径;

将项目上传到git:

  1. 先初始化,git init;

  2. 在idea中选择

  3. 提交项目到远程仓库:添加ignore文件在进行add . ,但是ignore文件也要提交上去,ignore文件的内部第一行就将自己给忽略了,我们要将它强制提交,或者删除第一行之后再提交;

    执行命令强制提交ignore文件:git add -f .gitignore

  4. 执行分支(仅第一次需要执行):git push -u origin master

在项目中添加gitignore文件;不加会把目录下的所有文件都提交到远程仓库;

上面命令需要gitignore文件:

第一次导入需要的:

命令行的方式推送:

 git remote add origin <git仓库复制的HTTPS路径>
 git push -u origin master

注意:这里因为创建仓库的时候已经有了一个.gitignore文件,上面做了强制add我们自己的文件,导致了文件名形同内容不同的情况,所以冲突了。所以,要么删除仓库的文件在推送,要么不推送这个文件。或者先拉取再推送:

 git pull origin master
 git push -u origin master


至此,仓库的初始化就完成了;


SSH认证远程仓库

config-server的配置文件中,这样的方式关联gitee不安全;工作中一般使用SSH的方式来连接。还有一种本地的方式配置,但这种方式不能热更新,用得少。


使用 git 作为远程配置仓库,除了使用账号密码进行认证意外,还可以使用 ssh 的方式进行认证,使用这样的方式可以避免你的账号密码泄露;

通过如下步骤来配置 ssh 认证方式:

第一步:生成ssh公钥和密钥

在任意目录打开 git bash,并执行如下命令,注意邮箱地址需要改成你自己的ssh-keygen.exe -t rsa -C "你的邮箱" + 3次回车即可。

第二步:设置远程仓库公钥

 1. 进入当前用户目录,并找到公钥文件 C:/Users/{username}/.ssh/id_rsa.pub,编辑后右键复制所有内容 2. 进入 https://gitee.com,进入自己 所在的仓库(如果不是仓库管理员,需要找管理员进行添加),点击仓库右边的管理按钮,进入管理页面后点击左侧菜单目录的部署公钥管理  3. 点击已启用公钥,并点击左侧菜单栏公钥管理下方的添加公钥  4. 进入页面后,标题可不写或随意写,在标题下方的文本框中粘贴第一步所复制的公钥内容,点击下方的添加按钮,返回到公钥管理界面看到启用公钥中有你刚刚添加的即可   第三步:修改 config-server 的配置文件  5. 在远程仓库克隆地址按钮处,选择 ssh 地址,并复制该地址  6. 将第一步所复制的地址粘贴到 config-server 配置文件中原本 uri 的位置  3. 删除 username & password 配置,并添加如下两个配置  ```yml ignore-local-ssh-settings: true privateKey: |         -----BEGIN RSA PRIVATE KEY-----             <your private key>         -----END RSA PRIVATE KEY----- ```

到此,ssh 配置就完成啦,完整配置如下:

 spring:   application:     name: config-server   cloud:     config:       server:         git:           uri: [git方式复制过来的地址]           ignore-local-ssh-settings: true           private-key: |             -----BEGIN RSA PRIVATE KEY-----              [复制过来的私钥内容]             -----END RSA PRIVATE KEY-----


测试:创建一个yml文件,启动配置中心服务,访问文件看看能不能获取到文件中的内容。



会员服务

添加MySQL相关的依赖:

 <!-- druid --> <dependency>     <groupId>com.alibaba</groupId>     <artifactId>druid</artifactId>     <version>1.1.10</version> </dependency> <!-- mybatis --> <dependency>     <groupId>org.mybatis.spring.boot</groupId>     <artifactId>mybatis-spring-boot-starter</artifactId>     <version>1.2.0</version> </dependency> <!--mysql驱动--> <dependency>     <groupId>mysql</groupId>     <artifactId>mysql-connector-java</artifactId> </dependency>

在远程配置仓库中创建会员yml文件添加配置:

 server:   port: 8090  spring:   datasource:     url: jdbc:mysql://localhost:3306/wolfcode_member?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8     driverClassName: com.mysql.jdbc.Driver     type: com.alibaba.druid.pool.DruidDataSource     username: root     password: admin     filters: stat     maxActive: 1000     initialSize: 100     maxWait: 60000     minIdle: 500     timeBetweenEvictionRunsMillis: 60000     minEvictableIdleTimeMillis: 300000     testOnBorrow: false     testOnReturn: false     testWhileIdle: true     poolPreparedStatements: true     maxOpenPreparedStatements: 20     validationQuery: select 'x'  mybatis:   configuration:     default-fetch-size: 100     default-statement-timeout: 3000     map-underscore-to-camel-case: true

连接MySQL的URL会有问题:注意添加编码和时区的问题



会员服务:

网络传输的实体类要实现序列化接口

MySQL中如果使用xml的方式,需要在启动类上贴:@MapperScan

现在用注解的方式所以不用贴。


Mapper:

Service和impl:

controller:

测试能不能查到数据;注意:我敲,void的controller你找错能找一个小时吗,void的返回,访问服务器查到数据也被掐死在半路了啊!!!

配置网关访问:

   sensitive-headers:   routes:     member-server-route:       path: /member/**       service-id: member-server       custom-sensitive-headers: true



用户登录:

引入前端项目;

前端:doLogin函数,发出登录请求:

 <script>     function doLogin() {         var mobile = $("#mobile").val();         var password = $("#password").val();          //发起ajax请求,请求带参数到后台查询用户信息         $.ajax({             url: "http://localhost:9000/member/users/login",             type: "POST",             data: {mobile: "", password: {}},             success: function (data) {                 //成功响应码200                 if (data.code == 200) {                     //成功,进入商品页面                     location.href = "/goods.html"                 } else {                     //失败提示                     layer.msg(data.msg)                 }             }         })     }</script>


完成之后commit一下;

处理用户登录;

因为是分布式微服务,用在服务端的session来存储的话,访问其他服务的时候获取不到会员服务中的session;选择将用户信息存在Redis中,存储的是以随机唯一数token做key,用户做value保存,让下一次请求带着token来Redis中查数据看用户是否登陆过;

浏览器端要将后台登陆成功后返回的token保存在cookie中,下一次请求将token放到请求头中带到后台,后台通过token查Redis中的用户信息来判断是否登录过。

更优的方案是:建议保存在请求头中,因为只有浏览器端才有cookie,所以对小程序移动端等场景就不适应了。


前台将token保存进cookie中,要让cookie生效必须保证下面三点:

  • 浏览器不能禁用token;

  • 一定要确定cookie不能被feign过滤掉;

  • ajax是默认不能操作浏览器cookie的,需要配置参数xhrFields: {withCredentials: true}


     //登录     @RequestMapping("/login")     public Result login(String mobile, String password, HttpServletResponse response) {         String token = userService.login(mobile, password);         //将 token设置到cookie中在浏览器端保存起来          // cookie生效的前提         // 1. 首先浏览器不能禁用cookie         // 2. ajax默认是无法操作cookie的,要想操作需要设置:加上参数:xhrFields: {withCredentials: true}         // 3. cookie 不能被zuul网关过滤,要加配置:sensitive-headers:custom-sensitive-headers: true         CookieUtils.addInCookie(response, "userToken", token);         return Result.success(null);     }



密码加密:

加密加盐:不管怎样加密,注册的时候加密后的密码保存之后,在他登录的时候,需要按同样的加密算法得到的密码去和数据库中的数据作比较,才能保证正确的密码能和密文匹配上。

 <script>     function doLogin() {         var mobile = $("#mobile").val();         var password = $("#password").val();         //和后台同样的加盐加密方式         password = "" + passsword_salt.charAt(0) + passsword_salt.charAt(2) + password + passsword_salt.charAt(4) + passsword_salt.charAt(6);         //对加盐后的值加密         password = md5(password);         console.log(password);           //1. 首先浏览器不能禁用cookie         //2. ajax默认是无法操作cookie的,要想操作需要设置:加上参数:xhrFields: {withCredentials: true}         //3. cookie 不能被zuul网关过滤,要加配置:sensitive-headers:custom-sensitive-headers: true         //发起ajax请求,请求带参数到后台查询用户信息         $.ajax({             url: "http://localhost:9000/member/users/login",             type: "POST",             data: {mobile: mobile, password: password},             xhrFields: {withCredentials: true},             success: function (data) {                 //成功响应码200                 if (data.code == 200) {                     //成功,进入商品页面                     location.href = "/goods.html"                 } else {                     //失败提示                     layer.msg(data.msg)                 }             }         })     }</script>


有状态服务器和无状态服务器

对服务器程序来说,有两个基本假设十分重要,究竟服务器是基于状态请求还是无状态请求。状态化的判断是指两个来自相同发起者的请求在服务器端是否具备上下文关系。如果是状态化请求,那么服务器端一般都要保存请求的相关信息,每个请求可以默认地使用以前的请求信息。而无状态请求则不行,服务器端所能够处理的过程,他的处理信息必须全部来自于请求所携带的信息以及其他服务器端自身所保存的、并且可以被所有请求所使用的公共信息。

 无状态的服务器程序,最著名的就是WEB服务器。每次HTTP请求和以前都没有啥关系,只是获取目标URI。得到目标内容之后,这次连接就被杀死,没有任何痕迹。在后来的发展进程中,逐渐在无状态化的过程中,加入状态化的信息,比如COOKIE。服务端在响应客户端的请求的时候,会向客户端推送一个COOKIE,这个COOKIE记录服务端上面的一些信息。客户端在后续的请求中,可以携带这个COOKIE,服务端可以根据这个COOKIE判断这个请求的上下文关系。COOKIE的存在,是无状态化向状态化的一个过渡手段,他通过外部扩展手段,COOKIE来维护上下文关系。
 状态化的服务器有更广阔的应用范围,比如MSN、网络游戏等服务器。他在服务端维护每个连接的状态信息,服务端在接收到每个连接的发送的请求时,可以从本地存储的信息来重现上下文关系。这样,客户端可以很容易使用缺省的信息,服务端也可以很容易地进行状态管理。比如说,当一个用户登录后,服务端可以根据用户名获取他的生日等先前的注册信息;而且在后续的处理中,服务端也很容易找到这个用户的历史信息。
 状态化服务器在功能实现方面具有更加强大的优势,但由于他需要维护大量的信息和状态,在性能方面要稍逊于无状态服务器。无状态服务器在处理简单服务方面有优势,但复杂功能方面有很多弊端,比如,用无状态服务器来实现即时通讯服务器,将会是场恶梦。



java学途

只分享有用的Java技术资料 

扫描二维码关注公众号

 


笔记|学习资料|面试笔试题|经验分享 

如有任何需求或问题欢迎骚扰。微信号:JL2020aini

或扫描下方二维码添加小编微信

 




小伙砸,欢迎再看分享给其他小伙伴!共同进步!


本文分享自微信公众号 - java学途(javaxty)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!