Java Web前后端分离项目—后端servlet实例


联合篇:前端靳紫澜的关于对接–前端

一、闲谈

从刚开始接到项目心中就一直惦记着该如何对接,究竟什么是对接。功夫不负有心人,前段时间与前端小姐姐对接成功了,在后端servlet编写中上网找了很多对接案例,对接方法。但大部分都很难,不易入手,也不易理解!所以在这里总结一下我的完整方式,前端的详细介绍请点击这位小姐姐的博客

前后端分离大大解放了程序猿(媛)的生产力,原来后台程序猿又写逻辑又写页面的时代一去不复返了(大佬例外)

但也同时产生了很多问题,例如沟通、接口文档、跨域等一系列问题。但这次疫情期间我们也不得以云对接了,前后端分离的开发模式也受到了很大的影响。在本篇博客中只谈后端的部分操作。

先说后台要解决的几个问题

  • json字符串的接受和发送
  • 跨域问题的解决
  • 对接出错后的纠错机制

二、json字符串的接受和发送

这里采用阿里巴巴的fastjson包,网上推荐原因是速度较快,但我觉得就冲国产也该支持一下。

这里不具体说明具体的json字符串和java对象的转化,主要说明json字符串在post方式下前后端的交互。(建议最好都用post方式,get方式请求不论是安全性还是数据限制上都有要求,难度也更高,不好统一)

json的发送

协议约定POST 提交的数据必须放在消息主体(entity-body)中(前端的json数据的名称设置为data,详情参考前端同学博客),但协议并没有规定数据必须使用什么编码方式(不是指字符编码),由开发者自行决定。服务端通常是根据请求头(headers)中的 Content-Type 字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。

因此POST 提交数据方案,包含了 Content-Type 和消息主体编码方式两部分。主要有四种方式:application/x-www-form-urlencoded、multipart/form-data、raw。

其中raw包含了application/json、text/xml。可以上传任意格式的文本,可以上传text、json、xml、html等

使用application/json 这个 Content-Type 作为响应头,用来告诉服务端消息主体是序列化后的 JSON 字符串。这种方案,可以方便的提交复杂的结构化数据。

raw方式使用的是纯字符串的数据上传方式,所以在来POST之前,可能需要手工的把一些JSON格式的数据转换成字符串的(加两自单引号)。在Postman利用post方式进行json测试https://www.yunliyunwai.cn/blog/detail/1a2387a41a0acd6cdb5ea37bb656011d,其他的在后端代码中并没有改动

json的接收

原来的是request.getParameter();这种事接收Params形式的数据,接收json已经力不从心了。而post是将内容放入请求体中,并另外专门开启了一个数据传输通道,其实是一个字节传输流 , 在Servlet 中 通过request.getInputStream(); 就可以获得这个字节流。(这只是其中的一种方式,还有很多方式等待我们去发现,就目前来说还是比较适用的)

BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream(),"utf-8"));
        //判断前端是否传过来json数据
        String body = IOUtils.read(reader);

IOUtils需要用到dubbo-2.5.3.jar,链接:百度网盘链接 提取码: ehyw

注意: 前期我们可能会下载很多版本的json转化包,而很多转化语句都是一样的,注意导入的jar包区别。

三、内网穿透或服务上云服务器

要想成功远程对接,就必须进行上述两种操作之一,让其他人可以访问你的网络地址。
先介绍NATAPP
什么是内网穿透?
内网穿透简单来说就是将内网外网通过natapp隧道打通,让内网的数据让外网可以获取。比如常用的办公室软件等,一般在办公室或家里,通过拨号上网,这样办公软件只有在本地的局域网之内才能访问,那么问题来了,如果是手机上,或者公司外地的办公人员,如何访问到办公软件呢?这就需要natapp内网穿透工具了。运行natapp隧道之后,natapp会分配一个专属域名/端口,办公软件就已经在公网上了,在外地的办公人员可以在任何地方愉快的访问办公软件了

内网穿透.jpeg

内网穿透可以做什么?

  1. 上文举例的办公软件
    
  2. 放在家里的树莓派,服务器等,需要远程ssh管理,这样打通服务器的22端口即可远程通过ssh操作服务器了.
    
  3. 微信/支付宝等本地开发.现在微信/支付宝等应用,需要服务器接收微信/支付宝发送的回调信息,然而在本地开发程序的话,还得实时上传到服务器,以便支持微信/支付宝的回调信息,如果使用了natapp内网穿透软件,将回调地址设置成natapp提供的地址,回调数据立即传递回本地,,这样很方便的在本地就可以实时调试程序,无须再不断上传服务器等繁琐且无意义的步骤.
    
  4. 一些企业内部数据库,由于安全等原因,不愿意放到云服务器上,可以将数据库放到办公室本地,然后通过natapp的tcp隧道映射,这样既保证安全,又保证公网可以正常访问.
    
  5. 一些开发板做的监控等信息,每台设备运行一条隧道,可以方便的管理监控各个设备的运行情况.
    
  6. 一些本地运行的游戏,想和好基友一起联网玩,一条命令运行natapp即可实现联网游戏.
    
  7. 群辉上运行natapp之后,随时随地在任何地方可以访问到群辉上应用
    

二、上云(云服务器)
请参考
学生领取阿里云服务器
阿里云配置Tomcat,数据库,java运行环境
孙伟峰同学的java项目上云

四、跨域

先来解决两个为什么

  • 为什么要跨域?
  • 如何做?

背景(为什么)

要了解为什么跨域,先了解来源—同源策略PDF介绍下载

同源策略是指在Web浏览器中,允许某个网页脚本访问另一个网页的数据,但前提是这两个网页必须有相同的URI主机名端口号,一旦两个网站满足上述条件,这两个网站就被认定为具有相同来源。此策略可防止某个网页上的恶意脚本通过该页面的文档对象模型访问另一网页上的敏感数据。

1995年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。

最初,它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源"。所谓"同源"指的是"三个相同"。

  • 协议相同
  • 域名相同
  • 端口相同

举例来说,"http://www.example.com/dir/page.html"这个网址,协议是http://,域名是www.example.com,端口是xx(默认端口可以省略)。它的同源情况如下。(scheme协议,host域名,port端口号)

URL结果原因
http://www.example.com/dir/page2.html只有路径不同
http://www.example.com/dir2/other.html只有路径不同
**http://**username:password@www.example.com/dir2/other.html只有路径不同
http://www.example.com:81/dir/other.html不同端口(若未标明,http:// 默认端口号为80)
https😕/www.example.com/dir/other.html[永久失效链接]不同协议httpshttp
http://en.example.com/dir/other.html不同域名
http://example.com/dir/other.html不同域名(需要完全匹配)
http://v2.www.example.com/dir/other.html不同域名(需要完全匹配)

目的:

同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。

设想这样一种情况:A网站是一家银行,用户登录以后,又去浏览其他网站。如果其他网站可以读取A网站的 Cookie,会发生什么?

很显然,如果 Cookie 包含隐私(比如存款总额),这些信息就会泄漏。更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。因为浏览器同时还规定,提交表单不受同源政策的限制。

由此可见,"同源政策"是必需的,否则 Cookie 可以共享,互联网就毫无安全可言了。

限制:

(1) Cookie、LocalStorage 和 IndexDB 无法读取。

(2) DOM 无法获得。

(3) AJAX 请求不能发送。

如何跨域

同源政策规定,AJAX请求只能发给同源的网址,否则就报错。

除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),还有几种方法规避这个限制。这里主要介绍Filter

  • JSONP
  • WebSocket
  • CORS
  • Filter

一:Filter介绍

Filter可认为是Servlet的一种“变种”,它主要用于对用户请求(HttpServletRequest)进行预处理,也可以对服务器响应(HttpServletResponse)进行后处理,是个典型的处理链。它与Servlet的区别在于:它不能直接向用户生成响应。完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
在这里插入图片描述

二:Filter的几个用处

在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest。

根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据。

在HttpServletResponse到达客户端之前,拦截HttpServletResponse。

根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。

三:Filter的种类

用户授权的Filter:Filter负责检查用户请求,根据请求过滤用户非法请求。

日志Filter:详细记录某些特殊的用户请求。

负责解码的Filter:包括对非标准编码的请求解码。

Filter可拦截多个请求或响应;一个请求或响应也可被多个请求拦截。

四:Filter的使用方法

方法使用**一个Filter只需要两个步骤:1.创建Filter处理类(如:MyFiletr)实现javax.servlet.Filter接口;2.web.xml中配置Filter

**注意:**在写Filter类时,IDEA中new — Creat New Filter(最下方的几个),而且不要多次写chain.doFilter(),这样会使一次请求发送两次响应。jsp页面内容翻倍

@WebFilter(filterName = "FilterTest")
public class FilterTest implements Filter {
    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
        //设置跨域请求
        HttpServletResponse response = (HttpServletResponse) res;
        //此处ip地址为需要访问服务器的ip及端口号
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type,Token,Accept, Connection, User-Agent, Cookie");
        response.setHeader("Access-Control-Max-Age", "3628800");

//        System.out.println("设置跨域请求");
        chain.doFilter(req, response);

//        chain.doFilter(req, res);这里注释掉这句话,因为前面已经将修改后的请求头发送了,这句话会使请求发送两次
    }

    @Override
    public void init(FilterConfig config) throws ServletException {

    }

}

在web.xml设置,将这段代码放入内

<!--     跨域设置 -->
    <filter>
        <filter-name>crossFilter</filter-name>
        <filter-class>FilterTest</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>crossFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

五、对接出错后的纠错机制

不论介绍如何,实践中总会出现各种各样的报错。404、400、500、无响应等等

下面介绍我的总结的纠错机制

  1. Tomcat的接口日志
  2. 控制台输出提示信息
  3. 在代码中添加判断条件,并依次给前端同学的信息中添加提示信息
  4. 对接成功,Navicat数据库做出响应

Tomcat的接口日志

如果添加了跨域后依旧对接失败,报如下错误

Access to XMLHttpRequest at ‘请求地址’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

这说明跨域依旧存在问题,检查自己代码。

跨域失败导致两个明显的情况

第一:前端的请求被前端浏览器拦截。

第二:前端请求正常,后端的响应被前端浏览器拦截。

如何检查呢?Tomcat贴心的为我们准备了可调整的对接日志。

IDEA下的每一个项目都会在默认的文件夹中建立此项目的配置和日志文件夹。默认用户目录Users

我的是E:\IDEA\system\tomcat\Tomcat_7_0_992_Dresult_Note\logs(已经迁移过了),打开后有5个日志文件,找到localhost_access_log.日期,就会显示接口的访问情况(日志格式根据自己喜好改动,每次更新都会刷新日期),注意:此日志在项目启动时不能打开,只有停止后才可以查看!

在这里插入图片描述

控制台输出提示信息

来回停止项目查看日志不是长久之计,我们可以根据自己项目实际情况在控制台输出提示信息,可以加入判断条件,根据不同情况做出不同提示。

前后端互动查错

对接从来都不是一个人的任务,一定要和前端同学保持密切的交流。我们最好可以在代码中添加浏览器输出信息的方式来给前端同学必要的回复。与判断条件配合使用。

完整代码如下

//导入的jar包省略,有些必要的jar包会在下方单独说明的
@WebServlet(name = "addNotesServlet",urlPatterns = "/servlet2/insertNotesServlet")
public class insertNotesServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        super.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        // 响应文本格式, json格式,必须设置
        response.setContentType("application/json;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        System.out.println("处理post()请求");

        //通过io流读取post提交的body,注意json数据只能用post方式提交,且在body请求体中,请求体没有名字。所以不能用getParameter获取,
        //post传输是另外专门开启了一个数据传输通道,其实是一个字节传输流 , 在Servlet 中 通过request.getInputStream(); 就可以获得这个字节流
        PrintWriter out = response.getWriter();
        BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream(),"utf-8"));
        String body = IOUtils.read(reader);

        //判断前端是否传过来json数据,输出到浏览器方式给前端提示,也可以打印在控制台上给自己看
        if(body.length()>0){
            out.println("<h2>恭喜您添加成功,辛苦啦</h2>\n");
            System.out.println("恭喜您添加成功:");
            out.println("<h2>这里是post方式有接受的测试接口,接受json数据返回相同的json数据,供前端小姐姐选择");
        }else{
            out.println("<h2>没有接受到数据哦,再想想哦!</h2>\n");
        }
        //原样返回前端输出的内容,起到验证作用,也可以查看自己的数据库是否更改,但最好给前端一个反馈
        out.write(body);

        //接受json类型的数据并转化,添加到数据库
        com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(body);
        String title = jsonObject.getString("title");
        String content = jsonObject.getString("content");
        String user_email = jsonObject.getString("user_email");
        String hasOpen = jsonObject.getString("hasOpen");
        String category = jsonObject.getString("category");
        NotesDao dao = new NotesDao();
        dao.insertNotes(title,content,user_email,hasOpen,category);
        //实例
        //{"title":"第一次尝试","content":"哈哈哈哈哈哈","user_email":"1142456160@qq.com","hasOpen":"yes","category":"test"}
    }
}

六、THE EHD

前端同学工作量不小,在对接前,后端同学一定要在本地Postman或其他测试工具上测试无误(跨域还是要实战测试),数据库有响应后再于前端同学对接。当然前端同学需要提前根据接口文档写好前端发送部分。完整的解决了对接是项目合并前的重要一步,也是平面迈向立体的跨越。在了解过程中查找了很多资料,不光是后端,前端的知识也是必要的,这能为和前端搭档对接时提供意想不到的帮助。

如果以上介绍有出错尽情指正,有其它方式欢迎留言或者交流啊!
参考文档
参考文档
参考文档
迁移IDEA默认工作目录
CORS跨域
Filter拦截器
解决中文乱码

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值