暑期实训报告

要注意,这一片博客仅仅是一篇作业。由于学院这样要求,所以是没有办法。因此,我也没有很认真去写,这本不应写的,只是这种腐朽的制度所迫。所以我也没怎么注意排版,盘古之白更是没有去注意。望周知。

生产(专业)实习报告

1、简介

1.1 实习背景

华中科技大学软件学院(生产)专业实习过程是每一届大三学生的必修任务,今年我们大三的学生当然也不例外。这个实习,其实我们更加愿意称其为实训,主要是训练我们的动手实践的能力,更具体一点,是锻炼我们的对于项目的了解和开发的能力。我们知道,我们软件学院的正统的课程都是偏理论性的,比如数据结构、算法设计与分析、计算机组成原理、操作系统等等,即使这些课程都会有相应的课程设计,并且也都是一个个小型的项目,但是这些都还是偏学术型的,它们对于锻炼我们的思维是很有帮助的,然而,在现代的互联网企业中,却很少会用到这样的技术,尤其是对于我们软件工程的毕业生来说。

那么,公司里面会用什么呢?以及,我们学生有必要去学习那些技术吗?我们的工程实训给了我们明确的答案,那就是要,而且很有必要,所以,我们学院在这样的情况下就展开了为期将近一个月的暑期实训,以期提高我们学生在工程项目中的动手能力以及对于项目的掌控能力。现代的企业需要的是什么?我觉得是成果,如果拿不出成果,那么,学再多的底层的知识也是排不上用场的,排不上用场的话,就会被社会淘汰掉。正如我们的先贤说过并且采取过的政策一样,我们首先要把别人的东西给搬过来用,然后再慢慢钻研它们的原理,然后再去想着超越他们。我觉得,我们的工程实训所起到的目的就是先让我们培养起拥创造项目的能力,先达到第一步的要求,然后等到将来发展到一定程度之后,就可以利用我们的理论课程上所学的知识,那时,我们的底层知识只会成为我们在技术方面的助力。综合这样的目的,我觉得学院开展这样的暑期实训是很有必要的。

1.2 实习情况

这一届的实习地点还是在软件学院的 5 楼的机房。这个氛围是比较亲切的,毕竟,平时的上机都是在这里。

对于这个地方,听说去年实训的时候,空调快掉了,好多学生埋怨,今年看来似乎已经没有了这样的问题,空调是比较凉快的,而且风口的同学似乎还比较冷。仔细一看,原来空调已经是换成新的了。不得不夸赞学院的行动力。当然,也有同学们的行动力。这二者是缺一不可的。今年似乎大二的学生也来到了这里实训,往常这里是只有大三的。让然,也好,这里的教室要小一点,方便教学,空调的效果也要好一些。

就学习情况而言,我们班一共安排了两位老师轮流来讲课。说起来,第一位老师还是我的老乡,聊起家乡的事情,是有点亲切的。当然啦,授课方面的话,两位老师都还行,毕竟讲的东西就是那些嘛。然而,由于时间的限制,我觉得,这个讲课还是很有水分的。为什么这么说呢,原因是我们学习的这些东西确实不能够在短短一两周内完成教学的,老师教得仓促,学生学得当然也是很仓促了。

1.3 实训内容

我觉得这个就应该叫做实训,而不应该叫做实习。原因是实习是应该正儿八经地到人家公司里面去,给人家干活,接触实际的生产内容,但是我们这个呢,还是在学校里面,其实际的形式也还是和学校的上课比较类似,然后小组作业,无非就是大作业罢了。

我们这一次的实训的主要学习内容还是 Java 开发,与去年不同的是,去年学习的 Spring 框架那一套,就是 Spring,Spring MVC,MyBatis 那些,而今年则有了变化,今年学习的内容首先上升到了 Spring Boot 这个层面,然后相比于去年多了一些内容,比如 MyBatisPlus,Spring Security,Redis 和前后端分离等等。数据库方面倒还是 MySQL,没有变化。

相较而言,我觉得今年最大的变化就是前后端分离这一块了吧。这个思想是现在企业开发的主流思想,学习这项技术当然是很有必要的。

2、Java 技术的工程应用

2.1 学习过程

2.1.1 学习内容介绍

首先我们是第一阶段的学习,主要学习后端开发技术。开发工具为 IDEA。

  1. Java 编程基础。这里呢,主要还是复习巩固 Java 的基础。然后查漏补缺,针对 Java8 和 Java11 和 Java17 的新特殊再进行专项的学习。这个部分进行的时间其实是不长的,毕竟之前是有基础的。主旋律是复习。复习基础内容。

  2. Java 高级编程。这里当然就是针对 Java 的新特性了。

这里就记录一下我的一些学习过程中的 Snippets,毕竟,林纳斯说过,"Talk is cheap, show me the code."。

将 String 类型的 List 转成 String 类型的数组。

1
2
3
4
List<String> list = Arrays.asList("hello", "test", "what");
System.out.println(list);
String[] strings = list.toArray(String[]::new);
System.out.println(Arrays.toString(strings));

将 Integer 类型的 List 转成 String 类型的数组。

1
2
3
4
List<Integer> integerList = Arrays.asList(1, 2, 3, 4);
System.out.println(integerList);
String[] intStrings = integerList.stream().map(a -> a.toString()).toArray(String[]::new);
System.out.println(Arrays.toString(intStrings));

List<Integer> 转为 List<String>

1
2
List<Integer> integerList = Arrays.asList(1, 2, 3, 4);
List<String> stringList = integerList.stream().map(a -> a.toString()).collect(Collectors.toList());

int[] 转换为 List<Integer>

1
2
int[] ints = {1, 2, 3};
List<Integer> list = Arrays.stream(ints).boxed().collect(Collectors.toList());

使用流式编程声明数组。

1
2
3
4
int [] myIntArray = IntStream.range(0, 100).toArray(); // From 0 to 99
int [] myIntArray = IntStream.rangeClosed(0, 100).toArray(); // From 0 to 100
int [] myIntArray = IntStream.of(12, 25, 36, 85, 28, 96, 47).toArray(); // The order is preserved.
int [] myIntArray = IntStream.of(12, 25, 36, 85, 28, 96, 47).sorted().toArray(); // Sort
  1. Web 前端开发技术,这里不再仅仅局限于简单的 html,css 和基础的 js,而是使用了成熟的前端框架 Vue。

Vue 是一个框架,也是一个生态。其功能覆盖了大部分前端开发常见的需求。但 Web 世界是十分多样化的,不同的开发者在 Web 上构建的东西可能在形式和规模上会有很大的不同。考虑到这一点,Vue 的设计非常注重灵活性和“可以被逐步集成”这个特点。根据你的需求场景,我们可以用不同的方式使用 Vue:

  • 无需构建步骤,渐进式增强静态的 HTML
  • 在任何页面中作为 Web Components 嵌入
  • 单页应用 (SPA)
  • 全栈 / 服务端渲染 (SSR)
  • Jamstack / 静态站点生成 (SSG)
  • 开发桌面端、移动端、WebGL,甚至是命令行终端中的界面
  1. Java Web 编程技术。

到了今天,提到 Java Web,也都是 Spring Boot 了。

Spring Boot是一个构建在Spring框架顶部的项目。它提供了一种简便,快捷的方式来设置,配置和运行基于Web的简单应用程序。

它是一个Spring模块,提供了 RAD(快速应用程序开发)功能。它用于创建独立的基于Spring的应用程序,因为它需要最少的Spring配置,因此可以运行。

简而言之,Spring Boot是 Spring Framework 和 嵌入式服务器的组合。

在Spring Boot不需要XML配置(部署描述符)。它使用约定优于配置软件设计范例,这意味着可以减少开发人员的工作量。

我们可以使用Spring STS IDE 或 Spring Initializr 进行开发Spring Boot Java应用程序。

为什么要使用Spring Boot Framework?

我们应该使用Spring Boot Framework,因为:

  • Spring Boot中使用了依赖项注入方法。
  • 它包含强大的数据库事务管理功能。
  • 它简化了与其他Java框架(如JPA/Hibernate ORM,Struts等)的集成。
  • 它减少了应用程序的成本和开发时间。

与Spring Boot框架一起,其他许多Spring姐妹项目也有助于构建满足现代业务需求的应用程序。 Spring姐妹项目如下:

  • Spring Data: 它简化了来自关系数据库和 NoSQL 数据库的数据访问。
  • Spring Batch: 它提供了强大的批处理处理。
  • Spring Security: 这是一个安全框架,可为应用程序提供强大的安全性。
  • Spring Social: 它支持与LinkedIn等社交网络集成。
  • Spring Integration: 它是企业集成模式的实现。使用轻量级消息传递和声明性适配器,它有助于与其他企业应用程序集成。

Spring Boot的优点:

  • 它创建独立 Spring应用程序,这些应用程序可以使用Java -jar 启动。
  • 借助不同的嵌入式 HTTP服务器(例如 Tomcat,Jetty 等),它可以轻松测试Web应用程序。我们不需要部署WAR文件。
  • 它提供了有用的' starter 'POM,以简化我们的Maven配置。
  • 它提供了production-ready功能,例如metrics, health checks和externalized configuration.。
  • 不需要 XML 配置。
  • 它提供了一个用于开发和测试Spring Boot应用程序的 CLI 工具。
  • 它提供了许多插件。
  • 它还最大限度地减少了编写多个样板代码(必须在几乎没有任何改动的情况下将其包含在许多地方),XML配置和注释的情况。
  • 它提高生产力并减少开发时间。

Spring Boot的限制:

Spring Boot可以使用应用程序中不会使用的依赖项。这些依赖性增加了应用程序的大小。

Spring Boot的目标:

Spring Boot的主要目标是减少 开发,单元测试和 集成测试时间。

  • 提供有目的的开发方法
  • 避免定义更多的注释配置
  • 避免编写大量导入语句
  • 避免XML配置

通过提供或避免上述几点,Spring Boot Framework减少了 开发时间,开发人员工作量并 提高了生产力。

  1. MySQL 开发基础,在这一部分,主要还是对 MySQL 数据库管理系统进行了学习和使用。

MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数据库管理系统)应用软件之一。

什么是数据库?

数据库(Database)是按照数据结构来组织、存储和管理数据的仓库。

每个数据库都有一个或多个不同的 API 用于创建,访问,管理,搜索和复制所保存的数据。

我们也可以将数据存储在文件中,但是在文件中读写数据速度相对较慢。

所以,现在我们使用关系型数据库管理系统(RDBMS)来存储和管理大数据量。所谓的关系型数据库,是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。

RDBMS 即关系数据库管理系统(Relational Database Management System)的特点:

1.数据以表格的形式出现 2.每行为各种记录名称 3.每列为记录名称所对应的数据域 4.许多的行和列组成一张表单 5.若干的表单组成database

RDBMS 术语。

我们先了解下RDBMS的一些术语:

  • 数据库: 数据库是一些关联表的集合。
  • 数据表: 表是数据的矩阵。在一个数据库中的表看起来像一个简单的电子表格。
  • 列: 一列(数据元素) 包含了相同类型的数据, 例如邮政编码的数据。
  • 行:一行(=元组,或记录)是一组相关的数据,例如一条用户订阅的数据。
  • 冗余:存储两倍数据,冗余降低了性能,但提高了数据的安全性。
  • 主键:主键是唯一的。一个数据表中只能包含一个主键。你可以使用主键来查询数据。
  • 外键:外键用于关联两个表。
  • 复合键:复合键(组合键)将多个列作为一个索引键,一般用于复合索引。
  • 索引:使用索引可快速访问数据库表中的特定信息。索引是对数据库表中一列或多列的值进行排序的一种结构。类似于书籍的目录。
  • 参照完整性: 参照的完整性要求关系中不允许引用不存在的实体。与实体完整性是关系模型必须满足的完整性约束条件,目的是保证数据的一致性。

MySQL 为关系型数据库(Relational Database Management System), 这种所谓的"关系型"可以理解为"表格"的概念, 一个关系型数据库由一个或数个表格组成,

  • 表头(header): 每一列的名称;
  • 列(col): 具有相同数据类型的数据的集合;
  • 行(row): 每一行用来描述某条记录的具体信息;
  • 值(value): 行的具体信息, 每个值必须与该列的数据类型相同;
  • 键(key): 键的值在当前列中具有唯一性。

MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。

  • MySQL 是开源的,目前隶属于 Oracle 旗下产品。
  • MySQL 支持大型的数据库。可以处理拥有上千万条记录的大型数据库。
  • MySQL 使用标准的 SQL 数据语言形式。
  • MySQL 可以运行于多个系统上,并且支持多种语言。这些编程语言包括 C、C++、Python、Java、Perl、PHP、Eiffel、Ruby 和 Tcl 等。
  • MySQL 对 PHP 有很好的支持,PHP 是很适合用于 Web 程序开发。
  • MySQL 支持大型数据库,支持 5000 万条记录的数据仓库,32 位系统表文件最大可支持 4GB,64 位系统支持最大的表文件为8TB。
  • MySQL 是可以定制的,采用了 GPL 协议,你可以修改源码来开发自己的 MySQL 系统。

2.1.2 学习过程中遇到的困难

由于之前没怎么接触过这个前后端分离的思想,所以这一次上手还是遇到了一些困难的。还有就是项目本身的话,由于小组的项目经验还是不怎么够,所以合作起来还是有一些捉襟见肘的地方的。还有就是需求分析,其实在真正的生产环境中,这是产品经理的工作,但是在我们这种同学之间组队开发的形式中,所有人都要参与这个产品的需求的讨论,然后就是这个工作其实并不简单,我在公司里面实习的时候,开发小组的产品经历都是资历很深的老员工,他们都是从开发转过去的,由于对技术非常熟悉,对开发很熟悉,所以像分析需求与开发之间的关系,定义接口之类的规范,他们对这个是非常严格的,最后订出来的成果也很好,很严谨。像我们的话,技术方面没有太深的积累,导致在分析需求的时候其实并没有怎么联系实际来看,导致后面开发起来还是比较困难的。而且,前端和后端这两块,由于大家都不怎么有经验,前端的话,主要是对 Vue 这个框架不太熟悉,主要是以前从来没有接触过,负责前端的小伙伴的困难其实是有点大的。老师们都说 Vue 很简单,那是建立在花费了一定的学习时间的情况下。如果让我花费了 500 小时学习任何一门框架,我都会说它很简单,上手起来很快的,但是呢,我们的实训的教学时间实在是太短了,这么短的时间急功近利给谁看呢?不太好。两头都想讨好,结果两头都顾不到,最后白白花费了那么多时间,做出一堆毫无意义的东西。

好吧,言归正传,还是学到了一点东西的。

遇到的一些困难主要是宏观方面的。小的方面呢,也就是一些 Java 的出错问题,好在这些到 StackOverflow 上一般都能够顺利解决。

然后前端方面呢,最开始的困难是不知道如何组织项目的文件,毕竟以前没有正儿八经的开发过 vue 项目。然后就是一些 js 方面的知识了。为什么呢?因为以前没有正儿八经的学习过 js,导致有些地方甚至连语法都不太熟悉。然后就是一些具体开发过程中的问题,什么跨域问题啦,什么路由解析问题啦,什么前后端对接问题啦等等。

后端方面主要的困难是 Spring Security 问题。配置问题。

还有什么问题呢,就是 git 和 github 的使用问题。由于网络原因,我们使用的是 gitee,其操作大概都是一样的。然后就是整体在处理 PR 的时候出现了一点问题。

2.2.3 实践心得

实践过程中的最大收获就是团队之间的合作。

然后呢,这一次的前端方面出现了一点问题,经验,还是经验的问题,毕竟以前从来没有这方面的经验,也不能把责任全部归在这个经验上面,但是总归是有问题的。前面的需求分析,小组之间的任务分工也没有做好,这就导致了后面在开发的过程中还要抽出大量的事件来讨论这个。其实是不应该。当然,这也给了我们下一次实践的教训。我们总结了教训,就是任务的前期一定要做好需求分析,软件过程管理十分重要,还有软件体系结构,这些是课上学过的,我们应该把他们合理的应用到实践中去,这样才能够学有所得。想起陈长清老师课上的教导,我觉得还是有些惭愧的,明明上课的时候对这方面已经讲了很多了,老师也给我们指导了很多方面,也学习了很多优秀的实践,可是最后确实没有用上多少,本来是应该用上的,这些在公司的实际生产中是很重要的。从需求到产品,每一步都要严格把关。

然后,学到的经验就是遇到不会的一定要及时请教老师,这一次说起来还是很感谢熊琳老师的帮助的,她甚至牺牲了一些午休的实践帮助我们的项目,可以说是老师的典范。

3、Java 技术在 Web 应用中的设计与实现

3.1 Web 技术简介

3.1.1 背景

Java Web,是用 Java 技术来解决 Web 互联网领域相关的技术总和。Web 包括:Web 服务器和 Web 客户端两部分。Java 在客户端的应用有 Java applet,但是早就被淘汰了。Java 在服务器端的应用非常的丰富,比如 Servlet,JSP 和第三方框架等。Java 技术对 Web 领域的发展注入强大的动力,好吧,为 Web 服务端的发展注入了强大的东西,客户端的话,脚本语言还是得看 JavaScript 的。嗯。

我们现在提到 Java Web 呢,都是指 Spring Boot 啦,至于纯粹古老的 Java Web,早就过时啦,现在已经没有人使用了,当然,现在流行的框架,像 Spring Boot 这些,其底层还是 Java Web 那一套的。这又是经典永流传的另一层体现,底层永不过时。

JSP 这些也早就过时了,像前两年还很流行 Thymeleaf 这个模板引擎来替代 JSP,现在也过时啦,现在讲究的是前后端分离。

3.1.2 前后端分离思想

” 前后端分离 “已经成为互联网项目开发的业界标杆,通过 Tomcat+Ngnix(也可以中间有个 Node.js),有效地进行解耦。并且前后端分离会为以后的大型分布式架构、弹性计算架构、微服务架构、多端化服务(多种客户端,例如:浏览器,车载终端,安卓,IOS 等等)打下坚实的基础。

前后端分离 (解耦) 的核心思想是:前端 Html 页面通过 Ajax 调用后端的 RestFul API 并使用 Json 数据进行交互。

注:【在互联网架构中,web 服务器:一般指像 nginx,apache 这类的服务器,他们一般只能解析静态资源。应用服务器:一般指像 tomcat,jetty,resin 这类的服务器可以解析动态资源也可以解析静态资源,但解析静态资源的能力没有 web 服务器好。】 一般只有 Web 服务器才能被外网访问,应用服务器只能内网访问。

为什么前后端分离?

一般公司后端开发人员直接兼顾前端的工作,一边实现 API 接口,一边开发页面,两者互相切换着做,而且根据不同的 url 动态拼接页面,这也导致后台的开发压力大大增加。前后端工作分配不均。不仅仅开发效率慢,而且代码难以维护。

而前后端分离的话,则可以很好的解决前后端分工不均的问题,将更多的交互逻辑分配给前端来处理,而后端则可以专注于其本职工作,比如提供 API 接口,进行权限控制以及进行运算工作。而前端开发人员则可以利用 nodejs 来搭建自己的本地服务器,直接在本地开发,然后通过一些插件来将 api 请求转发到后台,这样就可以完全模拟线上的场景,并且与后台解耦。前端可以独立完成与用户交互的整一个过程,两者都可以同时开工,不互相依赖,开发效率更快,而且分工比较均衡。

从 MVC 到前后端分离。

MVC 是一种经典的设计模式,全名为 Model-View-Controller,即 模型 - 视图 - 控制器。

其中,模型 是用于封装数据的载体,例如,在 Java 中一般通过一个简单的 POJO(Plain Ordinary Java Object)来表示,其本质是一个普通的 Java Bean,包含一系列的成员变量及其 getter/setter 方法。对于 视图 而言,它更加偏重于展现,也就是说,视图决定了界面到底长什么样子,在 Java 中可通过 JSP 来充当视图,或者通过纯 HTML 的方式进行展现,而后者才是目前的主流。模型和视图需要通过 控制器 来进行粘合,例如,用户发送一个 HTTP 请求,此时该请求首先会进入控制器,然后控制器去获取数据并将其封装为模型,最后将模型传递到视图中进行展现。

也就是说,我们输入的是 AJAX 请求,输出的是 JSON 数据,市面上有这样的技术来实现这个功能吗?答案是 REST。

REST 全称是 Representational State Transfer(表述性状态转移),它是 Roy Fielding 博士在 2000 年写的一篇关于软件架构风格的论文,此文一出,威震四方!国内外许多知名互联网公司纷纷开始采用这种轻量级的 Web 服务,大家习惯将其称为 RESTful Web Services,或简称 REST 服务。

可见,有了 REST 服务,前端关注界面展现,后端关注业务逻辑,分工明确,职责清晰。

认识 Rest 架构。

REST 本质上是使用 URL 来访问资源种方式。众所周知,URL 就是我们平常使用的请求地址了,其中包括两部分:请求方式 与 请求路径,比较常见的请求方式是 GET 与 POST,但在 REST 中又提出了几种其它类型的请求方式,汇总起来有六种:GET、POST、PUT、DELETE、HEAD、OPTIONS。

尤其是前四种,正好与 CRUD(Create-Retrieve-Update-Delete,增删改查)四种操作相对应,例如,GET(查)、POST(增)、PUT(改)、DELETE(删),这正是 REST 与 CRUD 的异曲同工之妙!需要强调的是,REST 是 “面向资源” 的,这里提到的资源,实际上就是我们常说的领域对象,在系统设计过程中,我们经常通过领域对象来进行数据建模。

REST 是一个 “无状态” 的架构模式,因为在任何时候都可以由客户端发出请求到服务端,最终返回自己想要的数据,当前请求不会受到上次请求的影响。也就是说,服务端将内部资源发布 REST 服务,客户端通过 URL 来访问这些资源,这不就是 SOA 所提倡的 “面向服务” 的思想吗?所以,REST 也被人们看做是一种 “轻量级” 的 SOA 实现技术,因此在企业级应用与互联网应用中都得到了广泛应用。

请求路径相同,但请求方式不同,所代表的业务操作也不同,例如,/advertiser/1 这个请求,带有 GET、PUT、DELETE 三种不同的请求方式,对应三种不同的业务操作。

虽然 REST 看起来还是很简单的,实际上我们往往需要提供一个 REST 框架,让其实现前后端分离架构,让开发人员将精力集中在业务上,而并非那些具体的技术细节。

前后端分离意义大吗?

1、该网站前端变化远比后端变化频繁,则意义大。

2、该网站尚处于原始开发模式,数据逻辑与表现逻辑混杂不清,则意义大。

3、该网站前端团队和后端团队分属两个领导班子,技能点差异很大,则意义大。

4、该网站前端效果绚丽 / 跨设备兼容要求高,则意义大。

术业有专攻(开发人员分离)。

以前的 JavaWeb 项目大多数都是 java 程序员又当爹又当妈,又搞前端(ajax/jquery/js/html/css 等等),又搞后端(java/mysql/oracle 等等)。

随着时代的发展,渐渐的许多大中小公司开始把前后端的界限分的越来越明确,前端工程师只管前端的事情,后端工程师只管后端的事情。

正所谓术业有专攻,一个人如果什么都会,那么他毕竟什么都不精。

大中型公司需要专业人才,小公司需要全才,但是对于个人职业发展来说,我建议是分开。

对于后端 java 工程师:

把精力放在 java 基础,设计模式,jvm 原理,spring+springmvc 原理及源码,linux,mysql 事务隔离与锁机制,mongodb,http/tcp,多线程,分布式架构(dubbo,dubbox,spring cloud),弹性计算架构,微服务架构(springboot+zookeeper+docker+jenkins),java 性能优化,以及相关的项目管理等等。

后端追求的是:三高(高并发,高可用,高性能),安全,存储,业务等等。

对于前端工程师:

把精力放在 html5,css3,jquery,angularjs,bootstrap,reactjs,vuejs,webpack,less/sass,gulp,nodejs,Google V8 引擎,javascript 多线程,模块化,面向切面编程,设计模式,浏览器兼容性,性能优化等等。

前端追求的是:页面表现,速度流畅,兼容性,用户体验等等。

耦合时代。

几曾何时,我们的 JavaWeb 项目都是使用了若干后台框架,springmvc/struts + spring + spring jdbc/hibernate/mybatis 等等。

大多数项目在 java 后端都是分了三层,控制层(controller/action),业务层(service/manage),持久层(dao)。

控制层负责接收参数,调用相关业务层,封装数据,以及路由 & 渲染到 jsp 页面。

然后 jsp 页面上使用各种标签(jstl/el/struts 标签等)或者手写 java 表达式(<%=%>)将后台的数据展现出来,玩的是 MVC 那套思路。

我们先看这种情况:需求定完了,代码写完了,测试测完了,然后呢?要发布了吧?

你需要用 maven 或者 eclipse 等工具把你的代码打成一个 war 包,然后把这个 war 包发布到你的生产环境下的 web 容器(tomcat/jboss/weblogic/websphere/jetty/resin)里,对吧?

发布完了之后,你要启动你的 web 容器,开始提供服务,这时候你通过配置域名,dns 等等相关,你的网站就可以访问了(假设你是个网站)。

那我们来看,你的前后端代码是不是全都在那个 war 包里?包括你的 js,css,图片,各种第三方的库,对吧?

好,下面在浏览器中输入你的网站域名(www.xxx.com),之后发生了什么?(这个问题也是很多公司的面试题)

我捡干的说了啊,基础不好的童鞋请自己去搜。

浏览器在通过域名通过 dns 服务器找到你的服务器外网 ip, 将 http 请求发送到你的服务器,在 tcp3 次握手之后(http 下面是 tcp/ip),通过 tcp 协议开始传输数据,你的服务器得到请求后,开始提供服务,接收参数,之后返回你的应答给浏览器,浏览器再通过 content-type 来解析你返回的内容,呈现给用户。

那么我们来看,我们先假设你的首页中有 100 张图片,此时,用户的看似一次 http 请求,其实并不是一次,用户在第一次访问的时候,浏览器中不会有缓存,你的 100 张图片,浏览器要连着请求 100 次 http 请求(有人会跟我说 http 长连短连的问题,不在这里讨论),你的服务器接收这些请求,都需要耗费内存去创建 socket 来玩 tcp 传输(消耗你服务器上的计算资源)。

重点来了,这样的话,你的服务器的压力会非常大,因为页面中的所有请求都是只请求到你这台服务器上,如果 1 个人还好,如果 10000 个人并发访问呢(先不聊服务器集群,这里就说是单实例服务器),那你的服务器能扛住多少个 tcp 连接?你的带宽有多大?你的服务器的内存有多大?你的硬盘是高性能的吗?你能抗住多少 IO?你给 web 服务器分的内存有多大?会不会宕机?

这就是为什么,越是大中型的 web 应用,他们越是要解耦。

理论上你可以把你的数据库 + 应用服务 + 消息队列 + 缓存 + 用户上传的文件 + 日志 + 等等都扔在一台服务器上,你也不用玩什么服务治理,也不用做什么性能监控,什么报警机制等等,就乱成一锅粥好了。

但是这样就好像是你把鸡蛋都放在一个篮子里,隐患非常大。如果因为一个子应用的内存不稳定导致整个服务器内存溢出而 hung 住,那你的整个网站就挂掉了。

如果出意外挂掉,而恰好这时你们的业务又处于井喷式发展高峰期,那么恭喜你,业务成功被技术卡住,很可能会流失大量用户,后果不堪设想。 注意:技术一定是要走在业务前面的,否则你将错过最佳的发展期。

此外,你的应用全部都耦合在一起,相当于一个巨石,当服务端负载能力不足时,一般会使用负载均衡的方式,将服务器做成集群,这样其实你是在水平扩展一块块巨石,性能加速度会越来越低,要知道,本身负载就低的功能 or 模块是没有必要水平扩展的,在本文中的例子就是你的性能瓶颈不在前端,那干嘛要水平扩展前端呢??? 还有发版部署上线的时候,我明明只改了后端的代码,为什么要前端也跟着发布呢???(引用:《架构探险 - 轻量级微服务架构》,黄勇)

正常的互联网架构,是都要拆开的,你的 web 服务器集群,你的应用服务器集群 + 文件服务器集群 + 数据库服务器集群 + 消息队列集群 + 缓存集群等等。

JSP 的痛点。

以前的 javaWeb 项目大多数使用 jsp 作为页面层展示数据给用户,因为流量不高,因此也没有那么苛刻的性能要求,但现在是大数据时代,对于互联网项目的性能要求是越来越高,因此原始的前后端耦合在一起的架构模式已经逐渐不能满足我们,因此我们需要需找一种解耦的方式,来大幅度提升我们的负载能力。

1、动态资源和静态资源全部耦合在一起,服务器压力大,因为服务器会收到各种 http 请求,例如 css 的 http 请求,js 的,图片的等等。

一旦服务器出现状况,前后台一起玩完,用户体验极差。

2、UI 出好设计图后,前端工程师只负责将设计图切成 html,需要由 java 工程师来将 html 套成 jsp 页面,出错率较高(因为页面中经常会出现大量的 js 代码), 修改问题时需要双方协同开发,效率低下。

3、jsp 必须要在支持 java 的 web 服务器里运行(例如 tomcat,jetty,resin 等),无法使用 nginx 等(nginx 据说单实例 http 并发高达 5w,这个优势要用上), 性能提不上来。

4、第一次请求 jsp,必须要在 web 服务器中编译成 servlet,第一次运行会较慢。

每次请求 jsp 都是访问 servlet 再用输出流输出的 html 页面,效率没有直接使用 html 高(是每次哟,亲~)。 6、jsp 内有较多标签和表达式,前端工程师在修改页面时会捉襟见肘,遇到很多痛点。

7、如果 jsp 中的内容很多,页面响应会很慢,因为是同步加载。

8、需要前端工程师使用 java 的 ide(例如 eclipse),以及需要配置各种后端的开发环境,你们有考虑过前端工程师的感受吗。

基于上述的一些痛点,我们应该把整个项目的开发权重往前移,实现前后端真正的解耦!

开发模式。

以前老的方式是:

  • 产品经历 / 领导 / 客户提出需求
  • UI 做出设计图
  • 前端工程师做 html 页面
  • 后端工程师将 html 页面套成 jsp 页面(前后端强依赖,后端必须要等前端的 html 做好才能套 jsp。如果 html 发生变更,就更痛了,开发效率低)
  • 集成出现问题
  • 前端返工
  • 后端返工
  • 二次集成
  • 集成成功
  • 交付

新的方式是:

  • 产品经历 / 领导 / 客户提出需求
  • UI 做出设计图
  • 前后端约定接口 & 数据 & 参数
  • 前后端并行开发(无强依赖,可前后端并行开发,如果需求变更,只要接口 & 参数不变,就不用两边都修改代码,开发效率高)
  • 前后端集成
  • 前端页面调整
  • 集成成功
  • 交付

请求方式。

以前老的方式是:

  • 客户端请求
  • 服务端的 servlet 或 controller 接收请求(后端控制路由与渲染页面,整个项目开发的权重大部分在后端)
  • 调用 service,dao 代码完成业务逻辑
  • 返回 jsp
  • jsp 展现一些动态的代码

新的方式是:

  • 浏览器发送请求
  • 直接到达 html 页面(前端控制路由与渲染页面,整个项目开发的权重前移)
  • html 页面负责调用服务端接口产生数据(通过 ajax 等等,后台返回 json 格式数据,json 数据格式因为简洁高效而取代 xml)
  • 填充 html,展现动态效果,在页面上进行解析并操作 DOM。

总结一下新的方式的请求步骤:

大量并发浏览器请求 ---> web 服务器集群 (nginx) ---> 应用服务器集群 (tomcat) ---> 文件 / 数据库 / 缓存 / 消息队列服务器集群

同时又可以玩分模块,还可以按业务拆成一个个的小集群,为后面的架构升级做准备。

前后分离的优势。

1、可以实现真正的前后端解耦,前端服务器使用 nginx。

前端 / WEB 服务器放的是 css,js,图片等等一系列静态资源(甚至你还可以 css,js,图片等资源放到特定的文件服务器,例如阿里云的 oss,并使用 cdn 加速),前端服务器负责控制页面引用 & 跳转 & 路由,前端页面异步调用后端的接口,后端 / 应用服务器使用 tomcat(把 tomcat 想象成一个数据提供者),加快整体响应速度。

这里需要使用一些前端工程化的框架比如 nodejs,react,router,react,redux,webpack 2、发现 bug,可以快速定位是谁的问题,不会出现互相踢皮球的现象。

页面逻辑,跳转错误,浏览器兼容性问题,脚本错误,页面样式等问题,全部由前端工程师来负责。

接口数据出错,数据没有提交成功,应答超时等问题,全部由后端工程师来解决。

双方互不干扰,前端与后端是相亲相爱的一家人。

3、在大并发情况下,我可以同时水平扩展前后端服务器,比如淘宝的一个首页就需要 2000 + 台前端服务器做集群来抗住日均多少亿 + 的日均 pv。

4、减少后端服务器的并发 / 负载压力

除了接口以外的其他所有 http 请求全部转移到前端 nginx 上,接口的请求调用 tomcat,参考 nginx 反向代理 tomcat。

且除了第一次页面请求外,浏览器会大量调用本地缓存。

5、即使后端服务暂时超时或者宕机了,前端页面也会正常访问,只不过数据刷不出来而已。

6、也许你也需要有微信相关的轻应用,那样你的接口完全可以共用,如果也有 app 相关的服务,那么只要通过一些代码重构,也可以大量复用接口,提升效率。(多端应用)

7、页面显示的东西再多也不怕,因为是异步加载。

8、nginx 支持页面热部署,不用重启服务器,前端升级更无缝。

9、增加代码的维护性 & 易读性(前后端耦在一起的代码读起来相当费劲)。

10、提升开发效率,因为可以前后端并行开发,而不是像以前的强依赖。

11、在 nginx 中部署证书,外网使用 https 访问,并且只开放 443 和 80 端口,其他端口一律关闭(防止黑客端口扫描), 内网使用 http,性能和安全都有保障。

12、前端大量的组件代码得以复用,组件化,提升开发效率,抽出来!

3.1.3 Java 与 Web 的关系

一般指的是 JavaEE,开发 Web 领域的应用。

而且,一般都是有框架的。

现在呢,则是前后端分离,我们观察淘宝京东这些网站就可以知道,在请求网页的时候,一般后台都是在请求大量的 json 数据,这个就是分离出来的后端返回的数据。

4、实习的收获与体会

本次实习的收获很多。

主要是对前后端分离这个思想学到了很多。

然后就是学会了团队之间的合作。有时候,一个项目不是一个人独自就能够完成的,这时候,寻找合作的伙伴是一件很明智的事情。以后到公司里面,一个项目,一个模块,也都不是一个人单独就能够完成的。如果要自己创业,一个人能够完成的事情其实也是有限的。


版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!