文档章节

传统JavaWeb项目前后分离实践

北风刮的不认真了
 北风刮的不认真了
发布于 2016/09/22 19:08
字数 2348
阅读 263
收藏 9

传统JavaWeb项目前后分离实践

很荣幸公司能分配给我前后分离的任务给我!给我这个js只会基础语法,也就能做做页面效果的人。到现在前后分离基本完成的阶段依然对nodejs基础一知半解,写这篇文章除了分享经验,也为能够抛砖引玉,能与大家探讨分离的技术

  • 前后分离的目的
  • 前后分离的过程
    1. 发现脚手架项目
    2. 启动脚手架
    3. 路由、处理404,500等错误
    4. 模块 request,log4js
    5. SpringMvc增加接口,jsp转html 以及 过滤器
    6. js跨域问题以及部署
  • 总结

前后分离的目的

我们公司是做会议网站,有一整套的会议邀请、会场互动、场外互动、会后传播的流程,每个模块下又有子模块,例如会场中抽奖,场外图文直播等,这些都是可以作为单独的服务来提供,并且可以单独客户定制某一模块。所以为保证灵活性和快捷开发,后台只提供接口,前端页面只让前端开发就好了,至少这样,,前端写页面时不用再启动eclipse了,后台去给前端配置环境!

前后分离的过程

1. 发现脚手架项目

讲真,作为一个javaer去搞前端框架开始有点不知道如何下手!唯一知道点的js开发就是NODEJS,因为我用来测试API的一个小软件就是nodeJs开发的,所以当时特意百度了解下。万幸google‘前后分离’,让我搜出来个nodejs前后分离的脚手架代码front-end-separate,让我有种刚了解java servlet后发现struts2感觉~

2. 启动脚手架

脚手架源码front-end-separate,它是基于express和grunt的前后端分离框架,引擎使用的是nunjucks。不知道express,grunt,nunjucks 这3是啥玩意,不管,先启动。
按照文档:

$ npm i grunt-cli -g
$ npm i
$ grunt

提示我better-npm-run不是内部命令什么的,google+百度,也没查出个大概来,无奈给作者发邮件询问,不能干等回复,又去了官网看better-npm-run文档,英文,不懂,试着执行了

$ npm i better-npm-run 
$ npm i
$ grunt

启动成功,看见首页啦!

3. 路由

nodejs的项目从代码看,还是挺简单的。
跟踪下脚手架里路由的配置文件。(我对这个了解过程与我写的顺序正好相反,因为开始我不懂express是什么)

var routes = require('./routes/routes');
var app = express();
routes(app);

通过这段代码,追踪到./routes/routes.js文件

module.exports = function (app) {

  require('./web/site')(app);
  require('./web/common')(app);

  // catch 404 and forward to error handler
  app.use(function (req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
  });
};

没有研究过nodejs模块具体怎么弄,但通过这块的代码,忍不住猜想,nodejs中模块引用,通过require(path) 获取 path对应文件中module.exports,可以是方法或者是对象

跟踪:./web/site.js
到这里就是正常请求的路由配置了! 在springMvc,写法如下:

@RequestMapping("/{projectId}/{status}.html")
	public String tmoduleData(@PathVariable String status,@PathVariable Long projectId,Model model){

特意查了下nodejs中路径中带有参数怎么弄,参考expressjs文档和众网友通过正则等获取参数方式 nodjs代码如下:

    //`:projctId` 可以通过 req.params.projectId 获得其值,如果其后面没有正则表达式(\\d+)限制为数字,则可以是任意字符~  
	app.get('/f/event/:projectId(\\d+)/:status(\\w+).html', function (req, res) {
		var request = require('request');
		request(app.get('APIDomain') + 'event/index?projectId=' + req.params.projectId + '&status=' + req.params.status, function (error, response, body) {
			
			if (!error && response.statusCode == 200) {
				var d = JSON.parse(body);
				d.projectId = req.params.projectId;
				d.status = req.params.status;
				d.EVENT_SITE_APIDomain = EVENT_SITE_APIDomain;
				res.render(d.data.returnUrl, d);
			}
		});
	});

关于其他参数的获取,例如post提交的参数等建议参考expressjs文档

4. 模块request、log4js

回顾上述的过程,就避不开2个开发中的需求

  • 如何发出http请求java后台数据
  • 如何记录日志

搜索关于nodejs中关于http的方法,深感原生的麻烦!如同以前开发网页时原生ajax请求和jquery.ajax()的对比,搜到request,cp代码,开始用!FUCK,我重启了好几遍grunt,为啥就是跑不通,就是不走我cp的代码!直到我npm i request才跑通!

为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统。 模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++ 扩展。

踩过request这个坑后,也就对nodejs模块化机制不是一无所知了,搜索刚刚的问题,还有一点,就是我没有错误的输出,控制台很空空如也!那么在nodejs中是否也有日志系统呢?
发现nodejs也有log4j,叫log4js 官方文档 参考众多网友的博客 如:http://blog.fens.me/nodejs-log4js/ 也写出了自己的第一个模块! 其功能有

  • 所有日志在控制台输出的同时也输出到日志文件中
  • 日志分类 并 输出到不同的日志文件中

具体参数参考文档吧,我就不啰嗦了

function getLog4js(){
	var log4js = require('log4js');
	log4js.configure({
		appenders : [{
				type : 'console'
			},
			{
				type : 'file',
				filename : 'logs/console.log',
				maxLogSize : 104800,
				backups : 100,
				category : 'console'			
			},
			{
				type : 'file',
				filename : 'logs/log4js.log',
				maxLogSize : 104800,
				backups : 100,
				category : ['[default]','eventSite','wxCaht']
			},
			{
				type : 'file',
				filename : 'logs/access.log',
				maxLogSize : 104800,
				backups : 100,
				category : 'access'
			}
		],
		replaceConsole : true
	});
	return log4js;
}

module.exports = getLog4js();

使用demo:

	var log4js = require('../../config/log4js');
	
	app.get('/', function (req, res) {
		console.log("app.get('env'):  "  +  app.get('env'));
		log4js.getLogger().info("默认 test");//默认的日志类型为'[default]'
		log4js.getLogger("console").info("console test", EVENT_SITE_APIDomain);//效果与console.log()一样
		log4js.getLogger("access").info("access test");
		log4js.getLogger("eventSite").info("eventSite test");
		
		res.render("index")
	});
//访问日志
app.use(log4js.connectLogger(log4js.getLogger('access'), {level:'INFO', format:':method :url'}));

5. SpringMvc增加接口,jsp转html

从jsp转html,我的思路是重构下代码,保留之前的功能不变,新增ajax请求的方法,因为无论springMvc的Model还是request.Attribute 都与Map结构类似,所以之前的要传给jsp的参数都put 到Map中并把这部分代码提取到一个方法中,然后之前的渲染jsp的方法和新的ajax方法都使用该方法return的MAP作为数据传给Modle或序列化就可以了

也是为了快速分离,所以我用了这种方法,实际上,有些地方应该再拆分的。我这样只能一个页面一个接口!

数据源解决了,开始把jsp改html吧!
jsp变html其实很简单,把jstl改为nunjucks模版的表达式就好了

做到这,不知道nunjucks是啥东西也就知道是啥了,这也算是个学习方法吧,一边用一边学,工作效率可能不高,但学习效率很高

遇到了几个坑:

1. 过滤器 slice 的使用

官方文档原文,真心读不懂,原谅我渣渣的英文!多次调用下,真心没搞懂,,请懂的大神给讲讲

slice(value, slices, fill_with=None)
Slice an iterator and return a list of lists containing those items. Useful if you want to create a div containing three ul tags that represent columns

没弄懂,最后还是自定义了fifter

	env.addFilter('sliceArray', function (a, start, end) {

		if (a instanceof Array) {
			start = start | 0;
			return a.slice(start, end);
		}
		return a;
	});

通过自定义的一些过滤器可以把jsp完美转成html

2. 在jsp中可以动态的include,而在nunjucks 没有找到类似的方法。

3. 渲染html的参数,没有全局的参数,js碰见跨域问题

渲染html的参数只能通过res.render(path, data);中data设置,全局参数是传不进去的,不知道其他人是怎么解决的,例如,我想在html中用到一个全局的参数,开发环境下页面AJAX请求的Domain和线上不一致问题,总不能上线前修改每个页面的domain吧
我的临时解决方案在下面部署部分说

6. js跨域问题以及部署

在自己的项目中,jsp里写的ajax url 无非在一个tag.jsp set了basePath,或window.jsPath,然后${basePath}/url。 而我们的更加简单粗暴,在同域名下的jsp都是相对路径 /url。
现在在nodjs开发过程中就出问题了,nodejs监听3001端口,tomcat端口9010,在localhost:3001下的页面访问loalhost:9010的ajax受到跨域限制!!!当然这是我开发的时候,前端开发时ajax肯定是个局域网内的一个服务器。

解决方案:

  1. 局域网内配置nginx add_header Access-Control-Allow-Origin *;
  2. 线上的策略简单多了,附上我的NGINX配置(我本地模拟上线时的场景)
	server {
        listen       80;
        server_name  song.yang.o;
        
        location / {
			proxy_set_header X-Real-IP $remote_addr;
			proxy_set_header Host $host:80;
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
			proxy_pass http://127.0.0.1:9010;
        }
		
		#处理nodjs路由的请求
		location ^~ /f/ {
			proxy_set_header X-Real-IP $remote_addr;
			proxy_set_header Host $host:80;
			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;	
			proxy_pass http://127.0.0.1:3001;
		}
		
		#nodejs下静态文件交由nginx处理
		location ^~ /static/ {
			root E:\\frontSeparate\eventSite\dist;
		}
    }

这样跨域问题就得到解决!

在说部署

吐槽下连个运维都没有的公司。。。

之前写的博客nodjs 服务器部署以及守护进程 这部分我没有啥发言权,我发邮件请教了脚手架作者,给回复:“线上建议pm2”

待我了解了pm2后再更新这里

总结

总结是啥玩意~~~

欢迎吐槽讨论~~

© 著作权归作者所有

北风刮的不认真了

北风刮的不认真了

粉丝 36
博文 53
码字总数 27105
作品 1
朝阳
后端工程师
私信 提问
加载中

评论(1)

青苗
青苗
文档写的很 nice 👏
前后端分离

前后端分离实践有感 前后端分离并不是什么新鲜事,到处都是前后端分离的实践。然而一些历史项目在从一体化 Web 设计转向前后端分离的架构时,仍然不可避免的会遇到各种各样的问题。由于层出不...

晨曦艾伯特
2018/01/11
266
0
前后端分离的思考与实践(二)

原文出处:淘宝UED - Herman 基于前后端分离的模版探索 前言 在做前后端分离时,第一个关注到的问题就是 渲染,也就是 View 这个层面的工作。 在传统的开发模式中,浏览器端与服务器端是由不...

淘宝UED - Herman
2014/04/18
0
0
基于API的前后端分离开发

传统MVC: CV的分离度差(Controller-View),不适用于多端开发。 前后联调的效率低下。 MIV: 一个后端,多个前端(Controller-Views)。 前后端完全分离,加快开发、测试速度。 前后端可以...

欧钟源
2015/10/03
317
0
synchronized/EasyCaptcha

EasyCaptcha JavaWeb图形验证码,支持gif验证码,可用于基于的session的web项目和前后端分离的项目。 效果展示 刷新页面可以重新生成验证码图片。 导入项目 gradle方式的引入 需要先在proje...

synchronized
2018/07/02
0
0
javaWeb 工程怎么搞打测试环境,生产环境war包

是传统的javaWeb项目,没有使用maven。怎么才能分开打包,测试环境,生产环境。请问能做到吗?在线等,求大牛解答

AlsaJasmine
2018/12/19
365
2

没有更多内容

加载失败,请刷新页面

加载更多

Podman 使用指南

> 原文链接:Podman 使用指南 Podman 原来是 CRI-O 项目的一部分,后来被分离成一个单独的项目叫 libpod。Podman 的使用体验和 Docker 类似,不同的是 Podman 没有 daemon。以前使用 Docker...

米开朗基杨
48分钟前
5
0
拯救 项目经理个人时间的5个技巧

优秀的项目经理都有一个共同点,那就是良好的时间管理能力。专业的项目经理会确保他们的时间投入富有成效,尽可能避免时间浪费。 时间管理叫做GTD,即Getting Things Done——“把事情做完”...

Airship
今天
6
0
LNMP环境介绍,Mariadb安装,服务管理,mariadb安装3

LNMP环境介绍 Nginx 处理的请求有两种,分为 静态与动态 图片,js,css,视频,音频,flash 等都是静态请求,这些数据都不是保存在数据库里面的 动态请求一般来说,需要的数据是在数据库里面...

doomcat
今天
1
0
前端技术之:Prisma Demo服务部署过程记录

安装前提条件: 1、已经安装了docker运行环境 2、以下命令执行记录发生在MackBook环境 3、已经安装了PostgreSQL(我使用的是11版本) 4、Node开发运行环境可以正常工作 首先需要通过Node包管...

popgis
今天
7
0
数组和链表

数组 链表 技巧一:掌握链表,想轻松写出正确的链表代码,需要理解指针获引用的含义: 对指针的理解,记住下面的这句话就可以了: 将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指...

code-ortaerc
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部