具体的业务逻辑在这里就不详细说了,主要来讲一下项目前后端的整体架构和其通讯问题。
1.项目整体架构:
后台利用springboot内嵌的tomcat作为服务器,负责业务逻辑的部分。
前台利用nginx作为服务器,负责数据展示的部分。
前后台利用Json结构的数据来进行通讯,数据格式如下:
{
"code": 0, //如果为0表示成功,如果大于0表示用户输入不符合条件,小于0说明为服务器内部错误
"message": "success", //如果code为0可以忽略这一项,不为0则直接提示这里的信息
"object": [{ //如果code不为0则可以忽略这一项,否则从这里取出真实需要的数据
...
}]
}
这里没有使用jsp或者thymleaf等框架来返回一个渲染后的页面,可以获得以下的优势:
- 前后端真正解耦,前后端可以各自开发,只需要利用协定接口进行通信即可。
- 更容易的发现bug,由于前后端可能的问题有各自特点,因此可以比较容易的定位bug。
- 减少后端服务器的压力,静态资源由nginx服务器获取到,后端只需要获取数据相关的动态资源。
- 接口易于重用,由于后端返回的数据是json字符串,因此即使以微信作为前端也只需要解析字符串并渲染即可,无需修改后端代码。
2.后台相关配置:
后台所要完成的是业务逻辑,具体来说就是从数据库中取出数据,进行一定的处理之后,以json字符串的形式返回给前台。
2.1.接口结构类定义:
package com.ctrl_i.springboot.dto;
import net.sf.json.JSONObject;
public class Envelope {
private int code;//代码
private String message;//提示信息
private Object obj;//携带对象
public static Envelope dbError=new Envelope(-1,"数据库错误!",null);//数据库错误
public static Envelope systemError=new Envelope(-2,"系统错误!",null);;//系统错误
public static Envelope success = new Envelope(0, "success", null);//成功
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public Envelope(int code,String message,Object obj) {
this.code=code;
this.message=message;
this.obj=obj;
}
public Envelope() {
}
public Envelope(Object obj) {
this.code = 0;
this.message = "success";
this.obj = obj;
}
@Override
public String toString(){
JSONObject jsonObject=new JSONObject();
jsonObject.put("code",this.code);
jsonObject.put("message",message);
jsonObject.put("object",this.obj);
return jsonObject.toString();
}
}
定义一个接口结构类有助于减少重复的代码量,并且规范返回前端的数据格式。
2.2.业务逻辑层描述
这里以获取文章列表的功能为例:
2.2.1.dao层:
dao层用于从数据库中取出需要的数据。
@Repository
public class ArticleDaoImpl extends BaseDaoImpl<Integer, ArticleEntity> implements ArticleDao {
@Override
public List<ArticleEntity> getOnePageArticleAfterId(int lastId, int pageSize) throws Exception {
String hql="from ArticleEntity where id>? order by id desc";
Object [] params={lastId};
return executeHQL(hql,params,0,pageSize);
}
}
2.2.2.service层:
service层调用dao层,将从其中取出的数据进行处理,并且将处理结果放入Envelope类中,返回类型为Envelope。
@Override
public Envelope getArticleList(int lastId) {
List<ArticleEntity> list;
try {
list=articleDao.getOnePageArticleAfterId(lastId,PAGE_SIZE);
} catch (Exception e) {
e.printStackTrace();
return Envelope.dbError;
... 省略部分逻辑
jsonObject.put("readNum",articleEntity.getReadNum()); //阅读数
jsonArray.add(jsonObject);
}
return new Envelope(jsonArray);
}
2.2.3.Controller层:
controller层调用service层,将从其中取出的Envelope类型序列化成字符串,然后通过http请求返回给前端,使其可以利用数据进行渲染。
/**
* 获取一页文章列表
* @param lastId 最后一条文章id
* @return
*/
@RequestMapping("/list")
@ResponseBody
public String getArticleList(@RequestParam(name = "lastId",defaultValue = "0") int lastId){
try{
return articleService.getArticleList(lastId).toString();
}catch (Exception e){
return Envelope.systemError.toString();
}
}
2.3.遇到的问题:
2.3.1.跨域问题:
在html页面中直接尝试获取后台的数据时,会提示跨域问题,通过查阅资料后发现这个问题很好解决,在Controller上添加一个注解即可:
@Controller
@CrossOrigin
@RequestMapping("/article")
public class ArticleController {
3.前端相关配置
3.1.nginx服务器配置
需要在nginx新加一个站点,并配置端口和项目根路径:
配置文件在/etc/nginx/site-available下
server {
listen 8081; #default_server;
listen [::]:8081; #default_server;
root /home/zekdot/ctrl_i;
index index.html index.htm index.nginx-debian.html;
server_name _;
error_page 404 /404.html;
location / {
try_files $uri $uri/ =404;
}
}
这里将项目根目录配置在了/home/zekdot/ctrl_i下,静态资源以后都放在那里,同时设置端口为8081,即访问 localhost:8081就能够访问到静态资源。
配置好之后重启nginx服务器,然后尝试访问放置好在对应的路径下的页面:
可见配置成功。
3.2.页面间数据传递及后台数据获取
3.2.1.页面间数据传递
可以通过cookies、url等方式来进行数据的传递,最终选择了解析url的方式来获取传递的参数,因为如果用户禁止了cookies的使用的话那么第一种方式就行不通了。
这里首先实现一个解析url的函数:
function getParam(url){
var url = url.split("?")[1];
var para = url.split("&");
var len = para.length;
var res = {};
var arr = [];
for(var i=0;i<len;i++){
arr = para[i].split("=");
res[arr[0]] = arr[1];
}
return res;
}
然后在页面中传入url解析出 参数名-参数值 的键值对即可:
var url=window.location.search; //获取url
id=getParam(url)['id'] //获取传过来的id
3.2.2.获取后台的数据
后台项目开启在8080端口上,因此只需要向这个端口请求数据即可,拿到数据之后再对页面进行填充。
/**
* 用于填充页面
*/
function putArt(str){
data=eval('('+str+')');
if(data.code!=0){
alert(data.message);
return;
}else{
arts=data.object
var nodes=""
...省略部分逻辑
nodes=$('<div class="blog-post-grids blog_grids></div>')
}
}
/**
* 得到下一页文章列表
* @param lastId
*/
function getNextPage(lastId){
$.post('http://121.250.213.120:8080/article/list',{'lastId':lastId},putArt);
}
最终得到的效果如下:
可见数据来源于后台的接口。