尚筹网项目大纲

  • 前言
    • 版本控制
    • 项目的维度
    • 注意点:
    • 项目防止表单重复提交
  • admin后台管理
    • 一、模块功能
    • 二、架构(ssm+ss)
      • 1、Spring整合mybatis
      • 2、事务管理器配置
      • 3、Spring整合SpringMVC
      • 4、登录安全设置(deprecate)
      • 5、项目的异常处理机制
      • 6、Spring整合SpringSecurity
    • 三、管理员前端模块环境搭建
      • 1 前端功能组件
      • 2 前端的请求分ajax请求和普通请求
      • 3 前端渲染方式:
    • 四 功能实现
    • 五 权限认证
      • 数据库层面
    • Handler为单位的资源权限设定
    • 整体架构
    • 模块详情
  • 命名规范
      • 1、路径命名规范
      • 2 模块命名规则
  • 部署
      • 修改点
    • 项目打包
      • 前端微服务打包
    • 会员微服务springboot打包
      • 开启项目运行环境

www.wzhtestcom

前言

项目架构:后台admin使用单一SSM架构,前台会员管理采用分布式架构,前后端的权限及安全统一采用SS架构
尚筹网项目大纲-编程知识网
开发模式:当下最流行的前后端分离模式(也混有一些jsp这种耦合开发的模式)
尚筹网项目大纲-编程知识网
前端的目的是显示后端传来的数据,后端的目的是操作和返回数据
前后端分类就是后端开发controller(SSM中依赖于service、mapper,微服务中则是依赖于openFeign提供的封装了handler的api)作为接口,和前端ajax数据交互,接收ajax传的json类型的参数并返回ResutEntity的结果

版本控制

情况一:通常出bug最冤的情况就是昨天完成的功能测试通过今天一运行就出bug了
情况二:遇到大大超出能力范围外的bug,不要犹豫立刻回退

解决方案:
以功能或功能组为单位进行提交,如果是大型功能也可以将当天的工作量作为单位进行提交,将当下刚完成某个新功能的项目纳入版本控制并提交到github,这样的话,针对情况一二线不要埋头修改bug而是直接回退

项目的维度

点 :一个个技术点
线:一个请求的处理过程,每个请求tomcat都会从线程池中拿出一个线程进行处理
面:多个请求交织在一起构成了一个完整的模块
体:多个模块构成一个完整项目

过程:聚焦于任务的实现 => 思路体现在流程图上 => 翻译成一行行注释 => 敲代码实现

目标 => 思路 => 代码

注意点:

1、命名要规范!规范!规范!见名知意,生动形象,最好参考阿里开发手册
2、对象除了自己new出来的和从IOC容器拿出来的可以直接用外,其余情况,例如从请求域,session/cookie域中拿出来的都要进行有效性判断,对象不为空,且数据长度大于0…
3、如果是n:n关系的两类实体,需要拆分出第三张表inner_xxx_yyy
4、分布式项目必备的模块:entity,api,service(eureka,nacos),gateway,provider(mysql,redis底层数据库的操作,服务提供方),consumer(服务接收方)
5、每写一个mapper层和service的方法最好都去先测试一番
6、ajax是默认异步的,但有时我们需要的是同步的效果,例如我们需要在ajax代码内展示通过ajax请求得来的数据,那么需要同步效果
7、养成惯性思维

  • 控制器类加@Controller,ajax请求处理器@RestController,里面的参数必须是@RequestBody类型,表示用于接收前端发送的json参数,异常处理用@ControllerAdvice
  • service层加@Service
  • 数据接口层只需要和Mapper实现类文件绑定即可
  • 配置类加@Configuration
  • 配置类中的组件加@Bean
  • 权限注解 @PreAuthorize(“hasRole(‘部长’)”),如要生效那么springsecurity注解一定要加@EnableWebSecurity
  • 前端引入的jquery最好提前放,因为很多第三方插件js都依赖于jquery,放到后面容易引发报错

项目防止表单重复提交

重复提交的三种情况

  • 如果是请求转发(url地址不变)的方式提交的表单,那么提交完表单后每按一次f5都代表发送了一个表单提交请求,这是最容易造成请求转发的情况了,表单提交的次数+1,只需要用重定向代替请求转发

  • 由于网络延迟(线程sleep)用户第一次点击按钮无效,点击多次

  • 用户提交成功,点击网页回退按钮

验证码的工作原理
验证码可解决问题二和三,原理是第一次生成验证码的存储在特定的session中,提交时会有比对操作,在登录信息正确基础上,如果相同那么验证成功且删除原先存储验证码的session,这样中途网络故障或故意回退都不会再通过

对于登录操作,注册操作,添加地址操作我们都需要使用重定向+表单验证码的方式进行

admin后台管理

尚筹网项目大纲-编程知识网

一、模块功能

componet模块

  • mapper接口层
  • mvc层①handler处理器层②config层,定义项目全局异常处理类,被@ControllerAdvice修饰的③interceptpr层④filter层
  • service层,下分为api和impl

webui模块
1)配置类文件(存储在resources根目录下的)

  • mybatis.mapper:存放实现mapper接口方法的xml文件
  • mybatis-config:mybatis全局配置文件,开启驼峰命名法
  • logback.xml 日志配置文件,指定①日志打印位置②日志打印格式③日志运行级别(全局info,和持久化层相关的部分设为debug,目的是观察sql执行过程)
  • spring-tx-persist.xml:Spring事物管理配置文件①扫描项目下和三类Controller无关的组件②为事物管理绑定已配置的数据源③配置事物切aop:pointcut面当做事物范围、aop:advioser作为具体的事物方法,选定一类方法作为事物方法,通过策略是根据service下的类命名风格,如AdminService,RoleService来将,来将整个service配置为切面,然后在tx:advice下指定为什么类型的方法开启事物控制,如为get/save/update/batch开头的增删改查方法开启事物控制
  • spring-mybatis-persist.xml:Spring整合mybatis配置文件①加载外部数据库配置文件,配置数据连接池②配置SqlSessionFactoryBean整合MyBatis,主要内容是指定mapper映射文件位置、mybatis全局配置文件位置、装配数据源③ 配置MapperScannerConfigurer来扫描Mapper接口所在的包
  • spring-web-persist.xml:Spring整合SpringMVC(web.xml中)后的SpringMVC的配置文件:①扫描项目下和三类Controller有关的组件②配置SpringMVC的注解驱动③配置视图解析器④配置基于XML的异常映射⑤配置view-controller⑥配置interceptor过滤器,但如果使用ss就注销掉这部分代码⑦配置sss全局注解标签,使ss注解标签生效
  • jdbc.properties:存储mysql数据库的连接信息

2)webapp:javaweb文件WEB-INF下web.xml是javaweb工程的全局配置文件,和众多html文件在一起,css/img/js等资源和WEB-INF文件夹都在webapp目录下

3)entity模块:只有对数据表的封装类模块

4)utils模块,同时被admin管理员模块和会员模块依赖,是一个全局性模块
①constant层

  • CrowdConstant存放整个全部自定义常量,起名尤其要做到见名知意①增强复用性与规范性②这里的常量基本上都是会话层session和前后端交换中间量ModelMap的key(标志字母如message,loginMember)和value提示信息(验证码已过期!请检查手机号是否正确或重新发送),或者用于前后端通信变量ResultEntity返回成功或失败信息,这样的设计在遗忘时可以统一来这里查
  • 补充:第三方接口(oss,alipay,messageConfirm)调用涉及大量常量管理,我们通常将常量的属性新建一个XxxProperity来管理,属性值在application.yml中管理,并用注解@ConfigurationProperties(prefix = “ali.pay”)来进行管理
  • AccessPassResources,定义一个PASS_RES_SET集合用于存储不需要拦截的路径,定义一个STATIC_RES_SET用于存放所有静态资源所在的目录,这个类存储会员模块zuul网关默认放行的静态资源和控制器url

②exception层:存放全部自定义异常,如账号已存在异常,账号登录失败异常…一个异常代表一个异常类,这些异常类在compoent的mvc模块用CrowdExceptionResolver来处理,这个类代表一个异常解析器,类里面的一个方法解析一个异常
③utils层:存储真正的工具方法有

  • Cookie操作工具类方法
  • ResultEntity,适用于做前后堵分离项目统一的ajax请求的响应体微服务模块间通信的数据结构
String result; //两个值,fail失败orsuccess成功
String message; //两个值,表示返回的信息
T data; //表示返回的json格式的response数据
失败方法是返回失败信息message
成功方法有两种,一是返回不带结果只带信息的,另一种是返回同时带结果和信息的
  • CrowdUtils项目专用工具类方法请求类型判断方法①md5加密方法②判断请求类型是普通请求还是ajax请求的方法③封装验证短信服务的方法④上传图片到oss的工具方法
  • messageHttpUtils:用于短信工具方法中请求第三方服务器的短信服务的工具类方放,主要是各类重载的doPost/doGet/doPut/doDelete方法
  • FaceUtils:人脸识别工具方法,由配置太复杂放到了auth模块,有①detect人脸检查方法②faceAdd将人脸加入到face_set方法③faceSearch:在face_set中寻找人脸的方法④ createFaceSet创建人脸集合的方法⑤getDetail获取当前人脸集合的方法
  • ImageUtils ①uploadImg:人脸识别上传图片工具类方法,将图片以转化为File类型上传到指定位置
  • faceHttpUtils:①内部维护一个map,用于存储加载api.properties配置文件后的内容②getBytesFromFile:读取File类型图片的字节到一个byte[]中③post/get请求方法④decode/encode方法

reverse模块
就一项内容,即resource下的generatorConfig,这是mybatis的逆向工程文件,生成mapper接口和mapper的xml实现类及entity数据库抽象实体类,我们将mapper接口放到componet模块下,生成的实体类放到entity模块,生成的mapper实现类放到webui模块下

注意:并不是每张表都对应实体类或业务场景,有的表只是起桥梁作用,用于管理两张表,或者理解为将一张复杂表拆分成两张简单表,例如inner-admin-role就可以被拆分为role,admin,inner-admin-role(这种表不需要抽象为entity)

总结:我们的自定义异常往往是在用户操作的实质情况抛出,抛出后被@ControllerAdvice修饰的异常处理类处理,主要进行跳转到相应的处理页面,如发送普通异常会转向system-error页面,发送用户登录信息错误异常跳转到admin-login页面…
技术环境
尚筹网项目大纲-编程知识网
项目架构图
尚筹网项目大纲-编程知识网

二、架构(ssm+ss)

1、Spring整合mybatis

尚筹网项目大纲-编程知识网
操作清单
1 导入相关依赖:通常导入componet模块这种操作数据库库的模块
2 编写jdbc.properties
3 编写mybatis-config全局配置文件
4 编写mapper接口层和mapper的xml实现层
5 编写mybatis-config ssm整合层
①引入jdbc.properity②配置druid数据源③配置sqlSessionFactory到IOC容器中组件,主要是装配数据源、指定mybatis的全局配置文件和xml现实类所在的包、装配DBHelper插件④配置Mapper接口扫描组件MapperScanConfigurer用来扫描mapper接口所在的包
注意点:我们的mapper的实现类放在了webui模块但是mapper接口在componet模块

项目日志搭建
意义是①查看程序的运行状态,尤其是查bug是比较有效②代替sout输出,因为sout本身是io流的,是非常损耗性能的
尚筹网项目大纲-编程知识网
思路:扣掉Spring中的commons-logging包,然后用jcl作为适配器来适配slf4j-api和logback

Logger logger = LoggerFactory.getLogger(Test.class);
logger.debug("级别一debug级别");
logger.info("级别二,info级别");
logger.warn("级别三,warn级别");
logger.error("级别四,error级别");	

DEBUG INFO WARIN ERROR指定谁都是只打印它自己和后面相关的
技巧:推荐全局使用INFO级别,对于mybatis所在的mapper接口包使用BEBUG来打印,出bug时可以将全局设为DEBUG,级别越高,项目越笨重,启动越慢

2、事务管理器配置

操作清单

1 新建spring-tx-persist.xml
2 自动包扫描项目下除了三类Controller外的组件
3 新建事物管理器组件,内部导入druid数据源,这样便于在事物操作过程锁住数据库
4 配置aop-config组件①内部配置aop公共切入点表达式pointcut②导入配置好的事物建议
5 事物建议:①指定事物方法②为相关的查询方法设置只读属性,让mybatis知道这是一个查询操作
6 注意:①tx-method标签的方法必须在切入点表达式范围下②测试类中需要引入spring-tx-persist.xml的位置

事物过程

1) 理论分析

try{connection.setAutoCommit(false); //aop前置方法,关闭自动提交operation sql   //执行sql语句,aop主方法connection.commit()  //aop后置方法,手动提交
}catch(Exception e){connection.rollback();//aop异常方法,出现异常回滚
}finally{connection.close();//aop结束方法,归还连接到连接池
}

2)日志打印信息

Creata a new transaction with name  xxxMethod
Switch JDBC connection to manul commit 
Create a new SqlSession
Register transaction synchorinization for SqlSession
JDBC connection will be manager by Spring

3、Spring整合SpringMVC

尚筹网项目大纲-编程知识网
1 web.xml中的相关配置
① 配置上下文参数context-param使得服务器一启动就通过ContextLoaderListener加载spring-mybayis和spring-tx这两个配置文件
② ContextLoaderListerner可以初始化IOC容器,使web应用中使用Spring提供的服务
③ 配置字符编码过滤器,这个过滤器一定要写在web.xml的最前面,统一编码格式为utf-8
④ springDispatcherServlet,在里面指定springmvc配置文件的位置和项目中的拦截路径(拦截路径基于两类不同的后缀名分类,分为.html和.json,分别代表普通请求和ajax请求,这两者请求分别返回html前端页面和json类型的处理结果)
⑤配置springsecurity的过滤器链,也就是拦截所有请求做安全检查

2 springmvc配置文件的内容
① 自动扫描被三类@Controller修饰的类所在的包
② 配置视图解析器
③ 配置SpringMVC的注解驱动 < mvc:annotation-driven/>
以上三个是必备的,还有两个常用的
① 配置view-controller,直接把请求地址和视图名称关联起来,不必写handler方法了,这种技术的需求是请求转发或重定向无法被视图解析器解析 => 需要重新再handler中写一个仅仅作为页面跳转的方法 => 不太划算,直接将这种操作用view-controller来完成对应关系
②配置基于XML的SpringMVC handler的异常映射
③注册拦截器

4、登录安全设置(deprecate)

1 拦截器
1)定义拦截器类implements HandlerInterceptor,实现它的三个方法,其中preHandle前者方法用于过滤请求,实现页面的访问权限设置。
方法是通过从session获取admin对象,获取到证明当前处于登录状态,放行,否则拦截
2) 注册拦截器到spring-web-mvc.xml中,其中设置拦截路径为全部路径,但是有几个必须默认放行①登录页面②退出页面

技巧:当不满足放行条件时我们不用急于返回false,因为返回false页面被拦截,展现给用户的是一片空白的页面,用户体验差且程序员也得不到bug提示信息。推荐方案是抛出一个自定义的异常,让mvc的异常解析器捕获然后进行处理,要么是跳转到登录页面让用户重新登录,或者跳转到错误页面打印错误信息…

注意:使用SpringSecurity那么就不再使用拦截器了,切忌两者共存,Springsecurity的用法及工作机制

5、项目的异常处理机制

分为两部分,一部分是专门处理SpringMVC的dispacherServlet拦截的异常路径,另一部分是处理SpringSecurity拦截的
两种不同请求的异常处理机制,差别在于返回错误信息步骤的不同,不同请求返回的是错误页面,ajax请求返回的是ResultEntity封装的实体对象
尚筹网项目大纲-编程知识网
请求的处理方法又可以分为基于注解的请求基于xml中的mvc:view-controller组件的方式
其中,基于注解的请求可能是普通请求也可能是ajax请求,所以异常处理起来比较复杂,基于xml的请求只能是普通的请求,异常处理起来比较简单
尚筹网项目大纲-编程知识网

1)基于xml的请求处理
在spring-web-mvc.xml中配置基于xml的异常处理器SimpleMappingExceptionResolver,在里面指定异常跳转页面system-error.html页面

2)基于注解的异常处理
①编写工具类CrowdsUtils的judgeRequestType工具方法来判断请是普通请求还是ajax请求
②CrowdExceptionResolver,大体分为两部分

  • 返回数据类型,需要先判断请类型,如果是ajax那就直接将错误以json字符串write到前端页面,如果是普通请求,经错误信息一并封装后以ModelAndView类型返回错误提示的页面信息
  • 针对不同异常类型的处理界面,大体分了三种①自定义异常处理错误,如LoginAcctAlreadyInUseException,LoginFailedException②常见jdk定义的exception,如NullPointException③兜底异常exception,也就负责处理不被上面两种异常类型涵盖的异常
  • 注意,不同的异常处理方法返回到不同的错误页面(普通信息)和错误提示json串(ajax请求)

3)处理springsecurity产生的异常
默认情况下这种异常是不会被拦截的,原理如下
尚筹网项目大纲-编程知识网
所以需要在springsecurity中进行异常处理配置

6、Spring整合SpringSecurity

前提:使用SpringSecurity前我们用该将admin-role-auth的关系组装好,把各个资源(菜单)所需要的权限设置好,初始化这些相关数据

作用:负责登录验证,权限验证…

1 主体principle:远程登录的用户
2 认证 authentication:根据主体的权限判断主体是否有操作某资源的权限
3 授权authorization:将某些权限授予主体
尚筹网项目大纲-编程知识网

整合
1、将依赖导入pom

2、在web.xml中配置SpringSecurity的Filter,这意味着SpringSecurity管理的不仅仅是SpringMVC的handler映射的请求,而是管理的是近乎全部web请求。但是要注意:filter-name只能是springSecurityFilterChain,且拦截路径最好是/*;
bug参考:https://blog.csdn.net/wwwwwww31311/article/details/113870039

3 spring-web-mvc中配置注解,目的是使权限注解生效,但因为controller的请求路径是由dispatchServlet拦截,并且controller组件最终是被扫描加入到了spring-web-mvc中,所以应该在此处开启ss注解如下

 <security:global-method-security secured-annotations="enabled"pre-post-annotations="enabled" jsr250-annotations="enabled"/>

3、创建配置类,需要@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true)这些注解,而且要保证被自动扫描到ioc容器中

public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {

4 ①在配置类中的两个configure中

  • 一个配置登录的用户名密码,需要创建userDetailsService实现类来配置权限验证的登录信息及角色身份,最好和admin的账号密码共用一套信息
  • 另一个springsecurity的访问路径规则,指定权限验证页面的jsp页面和访问路径,控制crsf和记住我功能的开关
    尚筹网项目大纲-编程知识网

② 配置密码加密规则,带盐值md5加密(BCriptPasswordEncode)
③ 配置PersistentTokenRepository类实现记住我功能,需要在mysql中创建指定的数据表,并创建和绑定源数据源
5 springsecurity需要搭建独立的异常处理体系,细节如上

三、管理员前端模块环境搭建

1 前端功能组件

1) 划分公共的头部、尾部、侧边栏区域
2 )公共头部分是最为通用的部分,几乎每个页面都有

  • 定义base基准路径,标准写法
  • 引入通用js/css/jquery资源

其中base的标准写法是:

<base href="http://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/>

3) 修饰system-error,主要①显示报错内容②返回上一页(达到从哪来回哪去的效果)的连接,本质是通过请求头来获取请求的地址信息
4) 在TestController和某jsp页面搭建ajax测试环境
尚筹网项目大纲-编程知识网
5 )前端界面搭建layer弹窗,好处是节省jsp页面,例如每个模块添加和修改都需要共用一张添加页面,这个页面可用弹窗代替,给程序瘦身

2 前端的请求分ajax请求和普通请求

①普通请求经handler处理 => 返回页面
② ajax普通请求经handler处理 => 返回json串
流程如下,需要在pom中依赖jackson,同时springmvc-web-perist.xml开启dirve驱动
尚筹网项目大纲-编程知识网

3 前端渲染方式:

尚筹网项目大纲-编程知识网
这种情况下前端要把页面一次性做出来交付给后端,典型的代表是jsp,这种页面中往往含有动态代码,这些动态部分要全部转化为静态,在将纯静态的页面响应回传到浏览器

前后端分离
前端(html img js css) 通过ajax请求的方式发送请求到后端开发的接口(此接口不是interface,而是mapper->service->controller),后端处理完毕统一返回所需的json格式的数据(通常要开会协调,指明数据格式ResultEntity),职责分明(前端接收并渲染数据,后端处理数据)

优点:

  • 应用程序的角度:程序耦合度大大降低,代码可读性与复用性增强,更容易找bug
  • 不必再将后台代码嵌入到前端代码(这一过程是在服务器端完成的),而是在前端通过js进行数据回显,相当于客户端分担了写服务器端的压力
  • 实际开发的角度:前后端人员同步独立开发,除了json格式外没有额外交集,各自专注于自己的领域,大大提高了开发效率

区别:

  • 前端渲染方法适合处理普通请求。handler中返回页面,一个动态的jsp页面,handler中处理得到的数据也会以变量的方式(el表达式)嵌入到这个动态页面中,但返回给浏览器的是被完全解析为常量的html页面,这种方式会使前端后端耦合比较严重。
  • 前后端分离适合ajax请请求,handler方法将目标数据以json或text的格式返回给前端,但不负责渲染,而是将数据用js的方法append到相应位置,这样真正的使前后端耦合度大大降低
  • 增删查模块这两种方法区别不大。其中修改方法中,前端渲染的修改方法是handler1负者先从数据库中查出把元数据展示到渲染好的页面a,用户在页面a修改完数据一并通过提交form将数据提交到handler2方法,在数据层面完成修改再转到相应页面,前后端分离的方法是
  • 如果是ajax请求,那么单个删除和批量删除用一套handler处理方法(也是一套sql,dao,service)即可,但对于普通请最好用两套,即单独删除和批量删除是分开来的

四 功能实现

1、完整的管理员登录模块
2、完整的管理员增删删改查模块
3、角色的增删改查模块
4、后台菜单栏的实现
5、给角色分配权限
6、oss配置与使用

五 权限认证

项目权限认证大纲

数据库层面

t_admin权限

id   login_acct      user_pwd   user_name  emaul
1	 tom        	#{password}	 汤姆	   1822014927@qq.com	
2	 adminOperator	#{password}	 AAOO	   1822014927@qq.com	
3	 roleOperator	#{password}	 RROO	   18220214927@qq.com	
273	 admin          #{password}	 王子晗	   2028965152@qq.com	

t_role
尚筹网项目大纲-编程知识网
t_auth

Handler为单位的资源权限设定

前提

  • 退出doLogout和登录doLogin操作(登录页面在springsecurity拦截器中需要放行)及登录成功跳转页的访问不需要其它任何条件
  • 能够成功登录admin后台管理,即使没有任何权限信息页默认具有admin管理员权限,admin权限可以有①会员维护(删查功能)②会员实名认证管理(通过or驳回) ③广告页面管理 ④项目管理(下线,查询)⑤权限类操作…需要权限来限制访问的页面如下

AdminHandler权限设计思路

拥有经理可以访问全部admin模块的权限普通其他角色:拥有admin:get可以进入admin主页进行整体查看和查询查看,但依然不能进行增删改以下三者默认是具有admin:get即查看admin列表首页的权限的拥有admin:save的角色可以保存(查看)admin拥有admin:remove的角色可以删除(查看)admin拥有admin:update的角色可以修改(查看)admin

RoleHandler 权限管理思路

role列表首页和查询功能只要有默认的管理员身份及以上就可以访问,即不需要额外的角色与权限
role的添加需要具有经理身份或者具有role:save
role的修改需要具有经理身份或者具有role:update
role删除都需要具有经理身份或者具有role:delete

ProjectHandler

查询功能:普通admin权限,不需要任何附加角色与权限
删除功能:具有经理权限或project:delete权限

MemberHandler

查询功能:普通admin权限,不需要任何附加角色与权限
删除功能:具有经理权限或member:delete权限

AssignHandler

查看角色权限(点击role中的分配按钮会展示出全部数据) :经理角色或roleShow:auth权限或assignRole:auth
给角色分配权限,需要有经理角色或assignRole:auth查看管理员的角色(点击admin栏角色设置框设置角色):经理角色或adminShow:role权限或assignAdmin:role
给管理员分配角色:具有经理角色或assignAdmin:role

角色类型

  • adminExt: 灵活分配权限,不固定
  • adminV1:具有对admin和role的操作权限,但不能进行权限指派
  • manager:具备一切权限,注意,该角色的通用性不再数据表中存储而是直接在java程序中调用
  • 经理

# 会员模块

整体架构

尚筹网项目大纲-编程知识网
1、每个类微服务的配置都是不同的,但每个微服务都要指定端口号和服务名,但实际上每个微服务的端口只在配置网关时使用,正式使用时一律用ip+网关的端口,服务名通常是在配置网关、注入Eureka服务中心时使用、openFeign中标识api端口
2、使用lombok ①日志包升级,直接通过依赖,使用@Sl4fj注解来标注类,更方便使用②大大简化entity层的开发,使用@Data代替getter/setter,同理有参无参也有相应的注解使用
3、consumer模块的运行基本上都会通过openFeign建立对依赖mysql和redis模块中handler层的依赖,也就是consumer模块运行前要先启动mysql和redis这两个模块(不启动这两个模块,api就无法动态将这两个模块的handelr封装),最后将consumer只需依赖到api模块就可使用api(通过里面的service)对这两个模块封装的方法
4、provider模块接收对象类型参数一定要使用@RequestBody,也就是转化成JSON格式数据进行处理,provider模块是要和底层mysql或redis数据库打交道的,ssm框架的底层进行数据交互依然是只认json格式
5、如果说PO是对数据表的封装,那么VO就是对开发中前后端交互字段的封装,而且因为要在网络传输的缘故还需要实现序列化
6、项目刚启动访问会报错,这并非是语法错误,而是模块注册到Eureka需要一段时间,导致那一时刻当前模块不工作,通常我们可以通过配置增加延迟时间

ribbon:ReadTimeout: 10000ConnectTimeout: 10000

7 网关的优点:

  • 为微服务云平台提供统一的入口(统一的ip+port)是API网关最主要的用途(不同的微服务往往对应不同的ip和port),掩盖了真实的端口提高了程序的安全性
  • 除此之外,网关还可承担认证授权、访问控制、路由、负载均衡、缓存、日志、限流限额、转换、映射、过滤、熔断、注册、服务编排、API管理、监控、统计分析等等非业务性的功能
  • 注意,微服务模块间跨端口重定向一定要使用完整的url,如
 return "redirect:http://localhost:81/auth/member/to/login/page";

但ssm环境中不推荐用完整url地址重定向,因为这样的话部署很容易出错,为了部署方便,一定不要使用模块的端口号,而是

return "redirect:/admin/get/page.html?pageNum=" +Integer.MAX_VALUE;

8、网关的注意点:
1)模块内部跳转的情况不需要考虑网关,如下

  • 直接跳转页面,
return "project-launch"; //即跳转到resoures/templetas/projectlauch.html页面下,不考虑路由
  • 模块内部配置的view-controller是不需要考虑,但是使用时(handelr进行重定向)需要考虑加一层网关
registry.addViewController("/return/info/page").setViewName("project-return");
return "redirect:http://localhost:81/project/return/info/page";

也就是进行模块通信必须使用微服务的统一入口网关api,但如果只是进行内部跳转就不需要考虑网关
2)cookie在不同端口号可以共享,根据同源策略cookie是区分端口的,但是对浏览器来说,cookie是区分域,不区分端口的,在一个ip地址下多个端口的cookie是共享的,但是因为微服务与微服务之间有安全级别Zuul内部有默认的过滤器,会对请求和响应头信息进行重组,过滤掉敏感的头信息:那么我们现在 不想丢失这些敏感信息,我们必须加入一个配制,让其跳过对头部敏感信息的初始化

sensitive-headers: #覆盖敏感信息  允许cookie 通过网关   加入这句 

我们只需要在其yml配置文件中 zuul网关下加入以下配置
3) 微服务解决session共享问题
尚筹网项目大纲-编程知识网
①重定向前后两个页面的数据传递需要session => session的建立依赖于cookie => cookie在微服务模块间通过网关配置和统一域名后可以共享
②模块间不同端口间的重定向无法共享session(每一个微服务模块本质是一个springboot,每个模块对应一个单独的springboot内置tomcat和一个单独的端口,虽然通过路由可以统一各个微服务的端口,但session的空间在tomcat内的,不同的微服务模块内置不同的tomcat就意味着一个独立的session,传统方案无法用session在模块间会话通信

完整过程:
浏览器发送cookie数据 => 服务器接收并处理cookie数据 => 服务器去它的redis中查找相应的session,没有就新建,新建的session要存入redis,将数据存入session回到redis
这个过程改变了session的默认存储位置,但从程序员的角度上并不想增加代码难度

方案一(不推荐):既然服务器端各个模块的众多session无法统一,那么就不用session,直接用cookie来代替session,因为用户只能从客户端浏览器发起请求,但是浏览器端的cookie数量是有限的且单个cookie最大4k,而且用户一单清理浏览器缓存就会丢失数据,不安全
方案二(推荐):搭建环境:在保证cookie共享的基础下,将每个需要模块间通信的模块(tomcat)都与共同的一个redis连接,并为这些有通信需求的模块配置springsession,这样就实现了数据共享,redis的优势:

  • session操作很频繁,redis(内存)速度快
  • session有过期时间,redis(内存)方便释放
  • springsession采用非侵入式设计,微服务间的session操作在引入依赖和配置后业务上操作和javaweb中一致,用户体验很好

10 配置ribbon,因为zuul/feign能够通过service-name调用eureka端注册的perovider是通过底层的ribbon来完成的,凡是注册进eureka的客户模块都推荐设置较大的超时时间避免和eureka的连接中断,尤其是第一次连接时需要链接的资源太多如果按照ribbon默认超时时长来的话很容易超时

11 对于操作频繁的数据或者需要及时清除的临时性数据,使用redis可以减轻mysql的读写压力,提高响应速度(用户体验),nosql的形式,不需要建表,操作方便,使用案例

  • 临时存储验证码用于校验,校验结束及时删除
  • springsession的实现底层依赖redis

模块详情

1、atcrowdfunding07-member-parent:
会员系统父模块,主要是进行依赖的统一管理和配置,无实际意义

2、atcrowdfunding08-member-eureka:
服务注册中心,为了增强应用容错性和实现负载均衡,我们通常会搭建两个及以上服务注册中心,核心思路是让两个eureka服务中心互相注册,相互守望,对外暴露出一个统一整体。同理负载均衡的实现原理就是让两个大体相同的provider在已注册集群的前提下共用一套application.name服务名,这样consumer模块工作是就可以轮询调用provider

3、atcrowdfunding09-member-entity:

实体类模块,有以下几种数据类型

  • VO,View Object用途是接收前端提交的数据封装成VO类型,然后将后端程序封装成VO对象发送给了浏览器,由于VO需要经网络渲染到前端,所以需要序列化也就是实现serialable接口
  • PO,Persistant Object用途是将数据封装为PO存入数据库,再次数据库取出的数据封装为PO类型,所以PO和数据库表是一一对应的,类似于ORM
  • DO,Data Object从第三方或中间件中取出的数据,如redis,zookeeper
  • DTO,Data Transform Object数据传输对象,用于Consumer和Provider的数据交互
    尚筹网项目大纲-编程知识网
    entity只需要导入lombok依赖,也就是省略getter/setter方法和构造方法等类结构,用注解代替,原理是在类运行时将这些结构动态以字节码的形式的加载到entity类的class文件中
    尚筹网项目大纲-编程知识网
    注意:idea需要去应用商店下载lombok插件

4 wzhfunding10-member-mysql-provider:
用于连接并交互mysql,配置类有以下任务(除了prot和serverName)

  • 在配置文件中配置连接数据库,配置整合mybatis
  • 注册进Eureka服务配置中心和微服务模块基本信息
  • 配置日志打印为debug,详细打印sql语句
  • 编写handler => 编写service的api和impl =>编写mapper接口和mapper映射文件 => 将handler暴露给api供consumer模块来调用
  • 启动类通过注解@MapperScan(“com.ccctop.cloud.mapper”)中指定mapper接口位置和标识Eureka客户模块的身份
  • 搭建测试环境测试mapper接口

技巧,下载Free Mybatis Plugin,然后mapper的接口和xml实现文件能通过小鸟的标志联通说明mybatis配置成功,可以使用

有和数据交互的全套组件mapper,service,handler且handler中的方法最终会被封装在第api模块中,被消费者模块调用。基本流程如下尚筹网项目大纲-编程知识网
5 atcrowdfunding11-member-redisserver-provider
该模块用于和redis交互,并创建方法操作redis的增删改查

  • application.yml中配置redis和注册进Eureka中
  • 该模块不需要mapper和service,仅仅编写handler即可,handelr中也只是一些简单的redis键值对的无超时创建,有超时创建,删除,获取,将handler的方法封装到api中的RedisService中,供consumer模块调用
  • 需要测试类进行测试远程连接Linux下的redis问题参考:https://blog.csdn.net/wwwwwww31311/article/details/113950464

6 atcrowdfunding12-member-authenticationserver-consumer

  • application.yml中配置服务名和端口、注册Eureka、配置redis和springsession、配置thymleaf、配置ribbon超时
  • 建一个config配置包,里面的配置类相当于SpringMVC配置文件的作用,进行view-controller视图映射
  • templates模板页需要指定基准页代表 ip:port/projectName/
  • 编写会员首页handler和用户注册、登录、验证码及一系列表单验证的handler
    尚筹网项目大纲-编程知识网

模块功能:
1 用户登录、注册、短信验证、表单验证、首页…
2 登录页面验证码功能
3 基于人脸的录入与签到

5、wzhfunding13-member-ps-consumer

  • application.yml中配置服务名和端口、注册Eureka、配置redis和springsession、配置thymleaf、配置ribbon超时,oss配置参数

5、atcrowdfunding16-member-zuulserver 网关模块
尚筹网项目大纲-编程知识网
尚筹网项目大纲-编程知识网

1、 application中注册eureka,配置redis,配置zuul, 启动类上通过@EnaleZuulProxy和使zuul生效
zuul的工作原理是通过application-name来标识主机,并为主机配置访问路径,如下

配置zuul,可以用网关的端口掩盖真正模块的端口,在通过给网关端口在host端口配置域名再次掩盖网关的端口,
routes:#这是路由id,没有固定规则;crowd-portal:#这是代理的模块服务名,该服务端口是4000service-id: ccctop-crowd-auth#这是路由匹配规则,也就是localhost:81/即代表localhost:4000/,下面的则是localhost:81/project/代表localhost:3000/path: /** # 这里一定要使用两个“*”号,不然“/”路径后面的多层路径将无法访问crowd-project:service-id: ccctop-crowd-projectpath: /project/**crowd-order:service-id: ccctop-crowd-orderpath: /order/**crowd-pay:service-id: ccctop-crowd-paypath: /pay/**

2 zuul除了项目网关功能外还有会员模块登录状态校验功能,也就是保护需要登录才能访问的资源,过程如下:
尚筹网项目大纲-编程知识网

  • 对于部分页面如登录退出方法和除了页面外的静态资源放行
  • 放行的内容封装为utils中的一个常量类 ,有首页、登录、注册、退出、发送验证码和除了页面外的全部静态资源(不放行那就无法渲染页面),思路是在这个静态类设置连个Set类型的属性分别存储handelr资源和静态资源,并创建一个判断是否为静态资源的方法
  • ZuulFilter的实现类CrowdAccessFilter用于会员模块的全局状态验证,shouldFilter()判断是否进行过滤检查,其中utils常量类有部分封装的指定页面和静态资源是不需检查的,run则相当于interceptor的prehandle方法,用于页面跳转前的验证,如检查到登录状态则可以跳转,否则默认先回到登录页面中
  • 配置请求头敏感,原理参考上述第九条

zuul除了utils还需要依赖entity,因为zuul的CrowdAccessFilter需要通过判断是否能从session域中取出MemberVO来做登录验证

6、atcrowdfunding17-member-api
通过openFeign封装了mysql和redis模块对外暴露的api方法,可以更方便的供consumer模块使用

4 atcrowdfunding17-member-api:api,顾名思义就是被调用的一方,通过了OpenFeign的技术封装了ccctop-crowd-mysql/ccctop-crowd-mysql服务的handler处理器方法,@FeignClient(“ccctop-crowd-mysql”)/@FeignClient(“ccctop-crowd-redis”)/,也就是封装了服务提供者的handler方法,自然要被消费者模块consumer来调用

命名规范

1、路径命名规范

路径的名称即是handler方法名的拆分,那么方法是如何命名的呢?

第一部分:和模块相关用户模块的连接用admin,菜单模块用menu,角色模块用role。

第二部分:
①用于表示handler中方法的性质,需要做数据处理(验证登录信息,数据修改,数据增加,数据删除)的用do②不做数据处理,而是单纯为了修饰页面再页面跳转的用to(这部分大多集中配置在了view-controller)③前端列表页(模块主页)用get

第三个
表示所处的前端位置①main表示处于index主页②add表示正处于前端添加页面③login表示正处于登录模块

第四个
除了handler的增删改方法其余都都对应page,也就是凡是和前端页面挂钩的都用page

第五
如果是对普通请求的返回用.html,如果是对ajax请求的返回用.json
注意:后缀名是强制性的,因为我们的springmvc的前端控制器就是基于后缀名规则进行拦截的

补充:
1凡是springsecurity进行处理操作的一律用security作为开头
2 微服务中直接使用的handler是consumer模块的,但consumer模块的ip+端口最终被网关统一的接管,我们要再为这个起一个项目级的名字即www.crowd.com网关

总之:
1、自定义方法名的好处是①保护作用,保护真实资源路径②自由发挥,通过对url的指定达到见名知意的效果
2、第一个标识模块的命名和最后一个后缀名是必须的,中间部分按照方法名来命名,通常分1-3段

2 模块命名规则

1、maven项目命名规则,有三部分构成

  • 第一个是wzhfunding+数字。这是是总项目名称,数字表示在总项目中排第几个
  • 第二个是表示模块所属类型,有admin管理员类型,member会员类型,common共用类型
  • 第三个是项目的类型,有webui视图模块,utils工具模块,componet组件模块,eurake注册中心模块,consumer是消费者模块provider是供给者模块

2、maven的包结构即为groupId,通常是组织域名,一个点就代表一个层级,admin管理模块中通常是两个层级即com.wzh刚好够用,但是会员微服务模块的maven模块需要三个层级,第三层命名相对随意,服务注册中心用cloud,其它用fund即可;aritifactId也是模块名,所以各模块的aritifactId是一致的,但是子模块需要和父模块共用一个groupId,而且在不考虑版本的情况下子模块可以和父模块共用父模块版本;
3、微服务springboot的启动类命名有三部分

  • 服务名开头,如Eureka,Zuul,Nacos
  • 中间用Main表示这是启动类
  • 最后用端口号来设置

4、微服务模块名application.name,也是三段,域名+项目名+技术名,其中微服务模块名、启动类名、项目名要保持一致的命名风格;

5 端口命名,模块间是有优先级的,优先级是server模块>接口方法提供模块provider>登录认证逻辑模块>消费者模块
优先级越大port越小,通过port可以达到优先级标识的效果,更好的体现依赖关系


部署

服务器绑定域名
尚筹网项目大纲-编程知识网

修改点

1、mysql数据库:管理员模块和会员模块中的的数据库连接配置密码需要修改
2、redis: 会员模块中的redis,auth,project,order,pay,zuul这些是和redis交互的模块
3、alipay涉及的url:在pay模块中替换
4、项目中凡是localhost:81/都需要需要使用118.190.133.64:81/来代替,排除Eureka,mysql,redis,entity,api这些个模块

技巧:先不要着急全部修改,先修改mysql和redis及其他中间件参数,以本机服务器连接服务器端mysql和redis…进行测试,测试通过在修改其他参数,这一步作为一个中间步骤
localhost的理解

  • java程序中,那些被服务器解析的localhost,就代表服务器端(阿里云ESC),其中配置文件(xxx.properties,xxx.yaml)中就可以使用localhost
  • 需要经浏览器解析的url一定不要用localhost,因为此时的localhost被浏览器解析后的内容就成了当前浏览器所在主机的ip地址了,有以下情况
1 前端页面中js的windows.href.location(js是在浏览器端执行的,
所以此处使用localhost比如被解析成浏览器端所在主机的ip)2 后端中重定向redirect:重定向的原理是告诉浏览器需要再次跳转的地址,
是浏览器自己的跳转行为,所有不能用localhost

页面跳转总结:只支持两种方式

  • 使用视图名,代表站内跳转
  • 如需要跳转到另一个handler,必须使用网关统一,无论是否跨端口,即便是本端口(本模块)的handler也要使用公网+网关统一端口,案例如下
return "redirect:http://118.190.133.64:81/project/return/info/page";

总之:项目中的跳转/请求转发/重定向,如果没有特殊情况,只是在模块内跳转是不可能使用localhost,项目跳转时使用 / 就可以代表ip:port/projectName;所以使用localhost进行跳转一定意味着是模块间的跳转,此时应该使用ESC服务器IP


项目打包

参考:maven的继承与聚合

前端微服务打包

尚筹网项目大纲-编程知识网

1、打包时关闭运行中的项目
2、管理员模块打包时先安装 common-util模块,因为在打包componet模块时,根据maven声明周期可知package是第五部,前几步有编译步骤,编译期间需要引用common-utils,所以我们需要提前安装好utils以便componet编译时依赖项中有common-utils.jar可用
3、声明打包类型为pom
总之:A依赖B,那么要先安装B再安装A;A与B是父子关系,那得先安装父工程,如果对聚合模块进行安装,那么它内部聚合的模块(modules标签)也会被顺序安装

4 打包命令:mvn clean install -Dmaven.test.skip=true
5 技巧,直接安装adminparent1管理员模块的父模块,然后在打包webui

最终我们需要获取的数webui.war项目结构,内容是在webui模块的webapp下的全部内容,外加①管理员模块的全部java类文件编译生成的二进制字节码文件,存于WEB-INF/classes文件下②管理员模块的全部第三方jar包,存储与WEB-INF/lib下,其中包括
尚筹网项目大纲-编程知识网

补充:
尚筹网项目大纲-编程知识网
此类情况配置以下插件

   <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.3</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding><compilerArguments><extdirs>${project.basedir}/src/main/resources/lib</extdirs></compilerArguments></configuration></plugin>

会员微服务springboot打包

  • 目标:通过java -jar xxx.jar可以直接启动springboot的jar包,此时要求这个jar包拥有内置tomcat、springboot环境jar包、依赖jar包
  • 方法:①为需要为微服务member-parent下除了entity和api外的全部微服务模块配置spring-boot-maven-plugin,不要再member-parent模块下配置,这样会作用于全部的微服务模块,而api和entity模块是不需要的②声明打包类型为pom,检查模块管理modules一定要正确
  • 技巧:直接对memberparent07进行打包,打包后的jar包去本地仓库,打包的jar包名字都很长,可以盖成简单好记的名字,方便启动

开启项目运行环境

尚筹网项目大纲-编程知识网
注意点:springboot打成可执行jar在linux上启动慢的问题/tomcat启动缓慢,往往是因为springboot内置tomcat启动时实例化SecureRandom对象随机数策略,解决方案是:springboot jar包启动慢
记录:重启阿里云ESC服务器后无论是tomcat启动还是springboot jar包的启动速度都变快

vim $JAVA_HOME/jre/lib/security/java.security
securerandom.source=file:/dev/random
改为
securerandom.source=file:/dev/urandom

注意:修改后执行reboot或重启阿里云服务器才有效

阿里云服务器和防火墙端口都需要特殊暴露四个端口8080,3306,6379,81,分别是tomcat,mysql,redis,crowd的默认端口,此外,阿里云ESC服务器端最好开发全部端口1-65536

而防火墙最好默认关闭,不要打开,防火墙操作如下

firewall-cmd --list-port  #验证防火墙是否已暴露需要的端口
systemctl start firewalld  #如果没有开启先打开
#Linux防火墙上开启8080,,3306,6379
firewall-cmd --zone=public --add-port=8080/tcp --permanent
#关闭防火墙/sbin/iptables -I INPUT -p tcp --dport 80 -j DROP 
systemctl restart firewalld

3 运行tomcat和redis
apache端口启动失败可能是防火墙原因

cd /usr/local/tomcat/tomcat8/bin  #跳转到..../startup.sh  #启动tomcatcurl localhost:8080 #验证启动是否成功

4 登录ftp工具或者

yum install lrzsz  #安装完可执行rz

5 会员系统的启动
会员系统采用springcloud微服务架构,不同于admin模块仅有一个webui.war,也不同于会员模块在idea上一口气全部启动,会员系统在服务器端以java -jar的形式运行需要遵循以下顺序

eureka服务注册中心服务2个 => mysql/redis模块(provider)2个 => 网关zuul模块 => 消费者模块3个