java|传统JavaWeb项目前后分离实践

2019独角兽企业重金招聘Python工程师标准>>> java|传统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 { listen80; server_namesong.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后再更新这里
总结 总结是啥玩意~~~
欢迎吐槽讨论~~
【java|传统JavaWeb项目前后分离实践】转载于:https://my.oschina.net/northerSong/blog/750365

    推荐阅读