什么是前后端分离开发?
前后端分离开发,就是在项目开发过程中,对于前端的代码专门由前端的开发人员开发,后端代码由后端人员负责,这样可以做到分工明确、各司其职,进而提高开发效率,前后端代码并行开发,加快项目的开发进度。目前前后端分离被各大公司使用,成为项目开发的主流开发方式。
前后端分离开发后,工程结构也会发生变化,即前后端代码不会混在同一个maven工程中,而是分为前端工程和后端工程。
- 后端:负责处理、存储数据。
- 前端:负责显示数据。
- 后端工程——>打包部署到tomcat。
- 前端工程——>打包部署到nginx。 前端和后端开发人员通过 接口 进行数据的交换。
开发流程
前后端分离开发时面临一个问题,就是前端人员和后端人员如何进行配合(请求路径、参数传递、请求方式、后端如何响应等)来共同完成一个任务呢?
接口(API接口):就是一个http的请求地址,主要就是去定义:请求路径、请求方式、请求参数、响应数据等内容。
- 后端编写和维护接口文档,在 API 变化时更新接口文档
- 后端根据接口文档进行接口开发
- 前端根据接口文档进行开发 + Mock平台
- 开发完成后联调和提交测试
推荐几个接口规范工具:postman、eolinker
前后端仅仅通过异步接口(AJAX/JSONP)来编程,前后端都各自有自己的开发流程,构建工具,测试集合,关注点分离,前后端变得相对独立并解耦合。
Swagger
Swagger是什么?
Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务的接口文档。
目前的项目基本都是前后端分离,后端为前端提供接口的同时,还需同时提供接口的说明文档。但我们的代码总是会根据实际情况来实时更新,这个时候有可能会忘记更新接口的说明文档,造成一些不必要的问题。
用人话说,swagger就是帮你写接口说明文档的。更具体地,可以看下面的图片,swagger官方建议使用下面的红字部分,这篇博客主要是记录如何,使用swagger自动生成Api文档的,所以只介绍swagger-ui,其他的…以后我用到会再整理。
基本使用
knife4j是java mvc框架集成swagger生成api文档的增强解决方案。
- 导入坐标
<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.3</version></dependency>
- 配置WebMvcConfig类
publicclassWebMvcConfigextendsWebMvcConfigurationSupport{/**
* 设置静态资源映射。
*
* @param registry
*/@OverrideprotectedvoidaddResourceHandlers(ResourceHandlerRegistry registry){
log.info("开始进行静态资源映射...");// addResourceHandler("/backend/**"):拦截请求信息,addResourceLocations("classpath:/backend/"):文件真实地址。
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");}/**
* 扩展mvc框架的消息转换器。
*
* @param converters
*/@OverrideprotectedvoidextendMessageConverters(List<HttpMessageConverter<?>> converters){
log.info("加入全局消息转换器...");// 创建消息转换器对象,MappingJackson2HttpMessageConverter messageConverter=newMappingJackson2HttpMessageConverter();// 设置对象转换器,底层使用Jackson将java对象转为json。
messageConverter.setObjectMapper(newJacksonObjectMapper());// 将上面的消息转换器添加到mvc框架的转换器集合中。放在集合的第一位,会先使用我们加入的全局消息转换器
converters.add(0,messageConverter);}@BeanpublicDocketcreateRestApi(){// 文档类型returnnewDocket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.basePackage("com.jie.reggie.controller")).paths(PathSelectors.any()).build();}privateApiInfoapiInfo(){returnnewApiInfoBuilder().title("瑞吉外卖").version("1.0").description("瑞吉外卖接口文档").build();}}
- 配置LoginCheckFilter类
/**
* @author 小杰 检查用户是否已经登录的过滤器。
*/@Slf4j@WebFilter(filterName ="loginCheckFilter", urlPatterns ="/*")publicclassLoginCheckFilterimplementsFilter{// 专门用来进行路径比较的。路径匹配器,支持通配符。publicstaticfinalAntPathMatcher PATH_MATCHER =newAntPathMatcher();@OverridepublicvoiddoFilter(ServletRequest request,ServletResponse response,FilterChain chain)throwsServletException,IOException{HttpServletRequest httpServletRequest =(HttpServletRequest) request;HttpServletResponse httpServletResponse =(HttpServletResponse) response;// 1.获取本次请求的uriString requestURI = httpServletRequest.getRequestURI();
log.info("获取到的uri:{}", requestURI);// 定义所有不处理的请求路径。String[] urls =newString[]{"/backend/**","/front/**","/employee/login","/employee/logout","/common/**","/user/login","/user/sendMsg","/doc.html","/webjars/**","/swagger-resources","/v2/api-docs"};// 2、判断本次请求是否需要处理,boolean check =check(urls, requestURI);// - 如果不需要处理,就直接放行,if(check){
log.info("请求不需要处理:{}", requestURI);
chain.doFilter(httpServletRequest, httpServletResponse);return;}// 3.判断登录状态,// 后台员工登录- 如果已登录,就直接放行if(httpServletRequest.getSession().getAttribute("employee")!=null){
log.info("用户已登录,登录的id为: {}", httpServletRequest.getSession().getAttribute("employee"));// 把id保存到当前ThreadLocal线程中。Long empId =(Long) httpServletRequest.getSession().getAttribute("employee");BaseContext.setCurrentId(empId);// 放行。
chain.doFilter(httpServletRequest, httpServletResponse);return;}// 用户登录- 如果已登录,就直接放行if(httpServletRequest.getSession().getAttribute("user")!=null){
log.info("用户已登录,登录的id为: {}", httpServletRequest.getSession().getAttribute("user"));// 把id保存到当前ThreadLocal线程中。Long userId =(Long) httpServletRequest.getSession().getAttribute("user");BaseContext.setCurrentId(userId);// 放行。
chain.doFilter(httpServletRequest, httpServletResponse);return;}// 如果未登录,则返回未登录结果.通过输出流方式向客户端响应数据。
httpServletResponse.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
log.info("用户未登录。。。");return;}/**
* 进行路径匹配,检查本次请求是否需要匹配。
*
* @param requestURI 待匹配的uri
* @param urls 所有不处理的请求路径数组。。
* @return 匹配成功返回true,否则返回false。
*/publicbooleancheck(String[] urls,String requestURI){for(String url : urls){if(PATH_MATCHER.match(url, requestURI)){returntrue;}}returnfalse;}}
参考
- 超详细的前后端分离开发
- swagger详解
版权归原作者 小杰不想秃头 所有, 如有侵权,请联系我们删除。