JavaWeb学习-Servlet处理解析JSON文件导出Excel实例

文章目录

  • 前言
  • 一、实例要求
  • 二、主要问题点
    • 1.保存请求中的文件
    • 2.JSON的简单处理
    • 3.Servlet共享数据
    • 实现勾选信息导出为excel
  • 三、源码
  • 总结


前言

这里是javaweb小白第一次尝试写博客,主要是想记录一下自己在学习JavaWeb的成长历程、记录在编写程序时解决的一些问题。也想借此帮助自己对知识点的消化和对代码结构体系上的深入理解,如果能帮助到同样正在学习这部分内容的小伙伴,那是莫大的荣幸!

回到正题,该篇讲解的是一个利用Servlet处理页面上传的JSON文件,对其解析后以表格形式呈现在响应页面,并可勾选相应的行下载导出excel文件。


一、实例要求

JavaWeb学习-Servlet处理解析JSON文件导出Excel实例_第1张图片

二、主要问题点

1.保存请求中的文件

首先我们要了解文件在http请求消息中的格式

我们通过表单向服务器发送包含了用户在浏览器页面上传的文件的http请求

<form enctype="multipart/form-data" method="post" action="fileUpload.do">
    <table border="1px">
        <tr>
          <td colspan="2" style="text-align: center">文件上传td>
        tr>

        <tr>
          <td>会员号:td>
          <td><input type="text" name="mnumber" size="30">td>
        tr>

        <tr>
          <td>文件名:td>
          <td><input type="file" name="fname" size="30">td>
        tr>

        <tr>
          <td style="text-align: right"><input type="submit" value="提交">td>
          <td style="text-align: left"><input type="reset" value="重置">td>
        tr>
    table>

form>

在form标签内 定义了编码类型enctype="multipart/form-data",并以POST方法发送请求。

关于enctype属性,在POST请求方法下默认为application/x-www-form-urlencoded,在这种编码格式下,数据会被编码成以被&分隔的健-值对的形式,健-对值之间以=分隔,也就是key=value

另一种text/plain纯文体的传输。空格转换为 “+” 加号,但不对特殊字符编码。这里不做过多介绍。

还有一种编码方式就是例中所用的multipart/form-data指定传输数据为二进制类型,比如图片、mp3、文件。表明表单数据为复合类型数据,包含多个子部分,这种方式提交的表单在我们的数据分离后,会以boundary开头、last boundary结尾。其中每个部分的描述都有HTTP头部描述子包体,如Content-type

对表单编码方式的介绍参考这篇文章,想要了解更详细内容可以点此查看该文章

我们使用wireshark抓取这个请求消息进一步解析
JavaWeb学习-Servlet处理解析JSON文件导出Excel实例_第2张图片
看到请求头Content-Type正文类型为multipart/form-data,对应了form标签内定义的编码类型。

表单的包体在http报文的正文内容,使用MIME多功能网际邮件拓展协议
JavaWeb学习-Servlet处理解析JSON文件导出Excel实例_第3张图片
图中第三行First boundary开始为第一个子包体,name="mnumber",是对应的请求参数名,该子包体以Boundary为标志结束

第二个part是请求中JSON文件,Content-Type:application/json表示了这个资源的类型,name="fname"是该资源的请求参数名,之后的代码中我们就会借助这个参数名来获取这个part,filename="javascore.json"是资源文件名

报文最后以Last boundary来结尾表明所有的资源文件都传输完毕。

由此条抓取的报文印证了multipart/form-data方式,复合型、多个部分、以boundary边界分隔的结构特征,能帮助我们从代码层面对请求包资源的操作理解。

String mNumber=request.getParameter("mnumber");
//获取上传的文件、request.getPart(“属性名”)用于获取使用multipart/form-data格式传递的http请求的请求体,通常用于获取上传文件。
//part.getSubmittedFileName();拿到文件名
Part part= request.getPart("fname");
//将上传的文件内容写入服务器文件中
part.write(fileSavingPath);

附上相应的代码语句,是不是就能更好地理解这些方法的含义

对于保存上传的文件到服务器,本例中采取了指定绝对路径的做法,这样做的缺点是只适用于一台服务器,不好做迁移。更好的解决办法是获取web项目在硬盘的绝对路径,再保存文件到web应用根目录的相对路径上。

为此我们可以使用servlet中用ServlertContext域的getRealPath()这个方法来动态的获取web应用的绝对路径(关于ServlertContext域将在后文介绍)

//参数"/"获取web应用输出根目录
String fileSavingFolder = this.getServletContext().getRealPath("/");

此方法有时候会遇到获取的路径在target文件夹下,这时需要更改tomcat服务器项目部署的输出目录至webapp文件夹下
JavaWeb学习-Servlet处理解析JSON文件导出Excel实例_第4张图片

2.JSON的简单处理

简单介绍一下JSON的格式

JSON三种格式:

(一)简单值:数字、字符串、布尔值
(二)对象形式:
JavaWeb学习-Servlet处理解析JSON文件导出Excel实例_第5张图片
(三)数组形式
数组形式
本例中的测试案例:
JavaWeb学习-Servlet处理解析JSON文件导出Excel实例_第6张图片
使用FastJson对JSON解析,当然也可以以字符串类型手动解析,只是比较繁琐。

FastJson环境配置非常简单,只需在pom.xml文件中加入以下依赖项,重新加载maven即可

<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>fastjsonartifactId>
    <version>1.2.47version>
dependency>

解析的思路:先读取文件内容到字符串数组再使用JSON.parseArray()转化为JSON数组,逐个取出对象进行解析

代码如下(示例):

        //获取存储在请求对象中的文件路径
        String filePath=String.valueOf(request.getAttribute("fileSavingPath"));
        //存储文件路径至全局作用域对象ServletContext中
        ServletContext application=request.getServletContext();
        application.setAttribute("filePath",filePath);
        //读取文件内容到字符串
        StringBuilder strJson= new StringBuilder();
        try {
            //设置字符编码UTF-8
            BufferedReader br=new BufferedReader(new FileReader(filePath, StandardCharsets.UTF_8));
            String str="";
            while((str=br.readLine())!=null){
                strJson.append(str);
            }

            br.close();
        }catch (IOException e){
            e.printStackTrace();
        }

        //转为JSON数组
        JSONArray jsonArray= JSON.parseArray(String.valueOf(strJson));
        System.out.println(jsonArray);

3.Servlet共享数据

因为对JSON文件的解析和导出excel的实现在两个不同servlet实现,所以需要servlet共享JSON文件路径,可以通过ServletContext对象来存储数据。

Web容器在加载每个Web程序时会创建一个唯一的ServletContext实例对象,该对象称为Servlet上下文对象。

//两种获取servletcontext的方法
ServletContext application=request.getServletContext();
ServletContext application=getServletConfig().getServletContext();

使用setAttribute(String name,Object object)getAttribute(String name,Object object)存储和提取数据

实现勾选信息导出为excel

实现样例:
JavaWeb学习-Servlet处理解析JSON文件导出Excel实例_第7张图片
思路: 通过getParameterValues()方法获取被选中的checkboxvalue数组
输出查看选中的value
依据数组选择对应顺序的JSON对象写入excel

设置报头Content-Encoding编码类型为gb2312
Content-Disposition是 MIME 协议的扩展,指示回复的内容、浏览器要以何种形式展示(以内联的形式即网页或者页面的一部分 or 以附件的形式下载并保存到本地)。
这里的字段值为"attachment; filename=\"学生成绩\""分别指定了文件以附件的形式下载和默认文件名。
Content-Type类型为"application/vnd.ms-excel;charset=gb2312"

三、源码

fileUpload.html


DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <style>
      form{
        margin-right: auto;
        margin-left: auto;
        width: max-content;
      }
    style>
head>
<body>
<form enctype="multipart/form-data" method="post" action="fileUpload.do">
    <table border="1px">
        <tr>
          <td colspan="2" style="text-align: center">文件上传td>
        tr>

        <tr>
          <td>会员号:td>
          <td><input type="text" name="mnumber" size="30">td>
        tr>

        <tr>
          <td>文件名:td>
          <td><input type="file" name="fname" size="30">td>
        tr>

        <tr>
          <td style="text-align: right"><input type="submit" value="提交">td>
          <td style="text-align: left"><input type="reset" value="重置">td>
        tr>
    table>

form>

body>
html>

FileUploadServlet.java

package com.example.excel;

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(name = "FileUploadServlet", value = "/fileUpload.do")
@MultipartConfig(fileSizeThreshold = 1024)
public class FileUploadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        PrintWriter out=response.getWriter();

        String mNumber=request.getParameter("mnumber");
        //获取上传的文件、request.getPart(“属性名”)用于获取使用multipart/form-data格式传递的http请求的请求体,通常用于获取上传文件。
        //part.getSubmittedFileName();拿到文件名
        Part part= request.getPart("fname");
        //反馈信息字符串
        String message="";

        //上传文件大小不能超过1MB
        if(part.getSize()>1024*1024){
            part.delete();
            message="文件太大,不能上传!";
        }else {


            //获得webapp根目录
            String fileSavingFolder = this.getServletContext().getRealPath("/");
            System.out.println(fileSavingFolder);
            //获得存储上传文件的完整路径(文件夹路径+文件名)
            //文件夹位置固定,文件夹采用与上传文件的原始名字相同
            String fileSavingPath = "C:\\Users\\Hana-bi\\Documents\\webfile" + File.separator + "students" + File.separator + mNumber;
            //如果存储上传文件的文件夹不存在,则创建文件夹
            System.out.println("文件路径:"+fileSavingPath);

            File f = new File(fileSavingPath);

            if (!f.exists()) {
                System.out.println("文件不存在!");
                f.mkdirs();
                System.out.println("目录已创建");
            }

            //获取HTTP头信息headerInfo=(form-data; name="file" filename="文件名")
            String headerInfo = part.getHeader("content-disposition");
            //从HTTP头信息中获取文件名fileName=(文件名)
            String fileName = headerInfo.substring(headerInfo.lastIndexOf("=") + 2, headerInfo.length() - 1);

            fileSavingPath+=File.separator+fileName;

            //将上传的文件内容写入服务器文件中
            part.write(fileSavingPath);

            message="文件上传成功~!";

            //使用request对象存储数据
            request.setAttribute("fileSavingPath",fileSavingPath);
            //获取转发对象
            RequestDispatcher rd=request.getRequestDispatcher("/Parsejson.do");
            //转发请求响应
            rd.forward(request,response);
        }

    }
}

ParseJsonServlet.java

package com.example.excel;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

@WebServlet(name = "ParseJsonServlet", value = "/Parsejson.do")
public class ParseJsonServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        /*
        第一步读取文件
         */

        //获取存储在请求对象中的文件路径
        String filePath=String.valueOf(request.getAttribute("fileSavingPath"));
        //存储文件路径至全局作用域对象ServletContext中
        ServletContext application=request.getServletContext();
        application.setAttribute("filePath",filePath);
        //读取文件内容到字符串
        StringBuilder strJson= new StringBuilder();
        try {
            //设置字符编码UTF-8
            BufferedReader br=new BufferedReader(new FileReader(filePath, StandardCharsets.UTF_8));
            String str="";
            while((str=br.readLine())!=null){
                strJson.append(str);
            }

            br.close();
        }catch (IOException e){
            e.printStackTrace();
        }

        //转为JSON数组
        JSONArray jsonArray= JSON.parseArray(String.valueOf(strJson));
        System.out.println(jsonArray);

        /*
        响应消息写入浏览器
         */
        PrintWriter out=response.getWriter();

        out.println("\n" +
                "\n" +
                "\n" +
                "    \n" +
                "    成绩\n" +
                "\n" +
                "\n" +
                "
"); out.println("
学生成绩列表"
); out.println("
");int no=1;//foreach或使用iteratorfor(Object ob:jsonArray){JSONObject jsonOb=(JSONObject) ob;String stuid=jsonOb.getString("stuid");String name=jsonOb.getString("name");String courseName=jsonOb.getString("courseName");String score=jsonOb.getString("score"); out.println(""+""+""+""+""); no++;} out.println("
序号学号姓名课程名成绩
+(no-1)+"\">"+no+""+stuid+""+name+""+courseName+""+score+"
"
); out.println("
"
); out.println(""
); } }

ExportScoreServlet.java

package com.example.excel;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

@WebServlet(name = "ExportScoreServlet", value = "/exportScore.do")
public class ExportScoreServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {


    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //注意编码为gb2312
        response.setHeader("Content-Encoding","gb2312");
        response.setHeader("Content-Disposition","attachment; filename="+ URLEncoder.encode("学生成绩.xls", StandardCharsets.UTF_8));
        response.setContentType("application/vnd.ms-excel;charset=gb2312");

        PrintWriter out=response.getWriter();
        out.println("序号\t学号\t姓名\t课程名\t成绩");


        //获取勾选的checkbox参数
        String []checks=request.getParameterValues("C");
        System.out.println(Arrays.toString(checks));

        //通过全局作用域对象获取先前存储的文件路径
        ServletContext application=request.getServletContext();
        String filePath=String.valueOf(application.getAttribute("filePath"));
        System.out.println(filePath);

        //读取文件内容到字符串
        StringBuilder strJson= new StringBuilder();
        try {
            //设置字符编码UTF-8
            BufferedReader br=new BufferedReader(new FileReader(filePath, StandardCharsets.UTF_8));
            String str="";
            while((str=br.readLine())!=null){
                strJson.append(str);
            }

            br.close();
        }catch (IOException e){
            e.printStackTrace();
        }

        //转为JSON数组
        JSONArray jsonArray= JSON.parseArray(String.valueOf(strJson));
        System.out.println(jsonArray);

        //将JSON对象写入excel
        try {
            for (String i:checks) {
                JSONObject jsonOb=jsonArray.getJSONObject(Integer.parseInt(i));
                String line=(Integer.parseInt(i)+1)+"\t"+jsonOb.getString("stuid")+"\t"+jsonOb.getString("name")+"\t"+jsonOb.getString("courseName")+"\t"+jsonOb.getString("score");
                out.println(line);
            }
        }catch (NumberFormatException e){
            e.printStackTrace();
        }


    }
}


总结

这是一个简单的Servlet上传、转发、响应的实例,同时也需要对html请求和响应消息格式、JSON格式的解析处理、ServletContext等作用域对象有清楚的理解,才能对程序有更好的实现。

第一次写这种技术文章,在整体逻辑的表达上还有欠缺,我也只是个初识JavaWeb的初学者,对相关知识的掌握比较浅显,如有纰漏和错误,欢迎指出!如果您有更好的实现方法也欢迎评论交流~

你可能感兴趣的:(JavaWeb学习,servlet,学习,json,java,tomcat)