传统JavaWeb项目前后分离实践

传统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后再更新这里

总结

总结是啥玩意~~~

欢迎吐槽讨论~~

转载于:https://my.oschina.net/northerSong/blog/750365

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值