下载APP

JSP | 基于Servlet和JSP改造oa项目

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情

目录

一: 基于Servlet和JSP改造oa项目

第一步:将原型中的.html文件,全部修改为.jsp文件

第二步:连接数据库,完成对应的操作

(1)index.jsp 跳转到 list.jsp

(2)list.jsp 跳转到detail.jsp

(3)list.jsp 跳转到 删除操作

(4)list.jsp 跳转到 add.jsp

(5)list.jsp 跳转到 modify.jsp


一: 基于Servlet和JSP改造oa项目

使用Servlet处理业务,收集数据; 使用JSP展示数据!

第一步:将原型中的.html文件,全部修改为.jsp文件

(1)将之前原型模板中的".html"文件,全部修改为".jsp",然后在所有的".jsp"文件头部添加page指令(指定contentType防止中文乱码),将所有的JSP直接拷贝到web目录下。

补充: ctrl+shift+del清除浏览器的缓存!

<%@page contentType="text/html;charset=UTF-8"%>

(2)完成所有页面的正常流转。(页面仍然能够正常的跳转,修改超链接的请求路径)

①这里就需要把所有的超连接路径更改,改成.jsp文件的格式;并加上项目名!

②这里就能体现出.jsp的优势,在jsp中是可以写java代码的;对于前端中的项目名,就可以通过java代码获取,不需要写死了!

③例如:对于欢迎页面index.jsp

<%=request.getContextPath()%> 在JSP中动态的获取应用的根路径
<a href="<%=request.getContextPath()%>/list.jsp">查看部门列表</a>

(3)目前所有原型页面如下:都是静态的页面,都是直接跳转到jsp展示数据,中间没有经过servlet获取数据!

①index.jsp 可以跳转到 list.jsp

<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>欢迎使用OA系统</title>
	</head>
	<body>
		<a href="<%=request.getContextPath()%>/list.jsp">查看部门列表</a>
		<hr>

	</body>
</html>

②以list.jsp为展开对象,可以跳转到:detail.jsp、modify.jsp、add.jsp

<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>部门列表页面</title>
	</head>
	<body>

<script type="text/javascript">
	function del(dno){
		// 弹出确认框,用户点击确定,返回true,点击取消返回false
		var ok = window.confirm("亲,删了不可恢复哦!");
		if(ok){
			document.location.href = "<%=request.getContextPath()%>/dept/delete?deptno=" + dno;
		}
	}
</script>

		<h1 align="center">部门列表</h1>
		<hr >
		<table border="1px" align="center" width="50%">
			<tr>
				<th>序号</th>
				<th>部门编号</th>
				<th>部门名称</th>
				<th>操作</th>
			</tr>
			<tr>
				<td>1</td>
				<td>10</td>
				<td>销售部</td>
				<td>
					<a href="javascript:void(0)" onclick="del(10)">删除</a>
					<a href="<%=request.getContextPath()%>/modify.jsp">修改</a>
					<a href="<%=request.getContextPath()%>/detail.jsp">详情</a>
				</td>
			</tr>
		</table>
		
		<hr >
		<a href="<%=request.getContextPath()%>/add.jsp">新增部门</a>
		
	</body>
</html>

③detail.jsp展示完以后在跳转到list.jsp

<%@page contentType="text/html;charset=UTF-8" %>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>部门详情</title>
	</head>
	<body>
		<h1>部门详情</h1>
		<hr >
		部门编号:20 <br>
		部门名称:销售部<br>
		部门位置:北京<br>
		
		<input type="button" value="后退" onclick="window.history.back()"/>
	</body>
</html>

④modify.jsp展示完以后在跳转到list.jsp

<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>修改部门</title>
	</head>
	<body>
		<h1>修改部门</h1>
		<hr >
		<form action="<%=request.getContextPath()%>/list.jsp" method="get">
			部门编号<input type="text" name="deptno" value="20" readonly /><br>
			部门名称<input type="text" name="dname" value="销售部"/><br>
			部门位置<input type="text" name="loc" value="北京"/><br>
			<input type="submit" value="修改"/><br>
		</form>
	</body>
</html>

⑤add.jsp展示完以后在跳转到list.jsp

<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>新增部门</title>
	</head>
	<body>
		<h1>新增部门</h1>
		<hr >
		<form action="<%=request.getContextPath()%>/list.jsp" method="get">
			部门编号<input type="text" name="deptno"/><br>
			部门名称<input type="text" name="dname"/><br>
			部门位置<input type="text" name="loc"/><br>
			<input type="submit" value="新增"/><br>
		</form>
	</body>
</html>

第二步:连接数据库,完成对应的操作

前面我们已经完成了jsp做数据展示的操作,但是并没有进行连接数据库;所以要先跳转到servlet完成数据的收集操作,然后通过servlet再跳到jsp做数据展示的操作!

(1)index.jsp 跳转到 list.jsp

(1)先对index.jsp模板原型进行修改;把超链接路径修改为跳转到一个servlet

<a href="<%=request.getContextPath()%>/list.jsp">查看部门列表</a>
<!--修改为-->
<a href="<%=request.getContextPath()%>/dept/list">查看部门列表</a>

(2)通过注解式开发,连接数据库,取出数据!(要有封装对象的意识---面向抽象编程

此时取出的数据实际上是很零散的,所以不妨封装一个Dept对象,把取出来的数据封装到这个对象里面。同时在创建一个ArrayList集合depts,把所有的对象在放到这个集合里。然后在通过请求域调用setAttribute方法,把这个集合放到请求域当中。最后在调用getRequestDispatcher方法,通过转发的方式调转到另一个jsp进行数据的展示

①封装的Dept对象用来存放取出来的零散数据

package com.bjpowernode.oa.bean;

import java.util.Objects;

/**
 * 普通的java类,张个java类可以封装零散的数据
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.oa.bean
 * @Project:JavaWeb
 * @name:Dept
 * @Date:2022/11/28 10:59
 */

public class Dept {
    private String deptno;
    private String dname;
    private String loc;
    // 构造方法
    public Dept() {
    }
    public Dept(String deptno, String dname, String loc) {
        this.deptno = deptno;
        this.dname = dname;
        this.loc = loc;
    }
    // setter and getter
    public String getDeptno() {
        return deptno;
    }
    public void setDeptno(String deptno) {
        this.deptno = deptno;
    }

    public String getDname() {
        return dname;
    }
    public void setDname(String dname) {
        this.dname = dname;
    }

    public String getLoc() {
        return loc;
    }
    public void setLoc(String loc) {
        this.loc = loc;
    }

    // 重写toString方法
    @Override
    public String toString() {
        return "Dept{" +
                "deptno='" + deptno + ''' +
                ", dname='" + dname + ''' +
                ", loc='" + loc + ''' +
                '}';
    }

    // 重写equals方法 和 hashCode方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Dept dept = (Dept) o;
        return Objects.equals(deptno, dept.deptno) &&
                Objects.equals(dname, dept.dname) &&
                Objects.equals(loc, dept.loc);
    }

    @Override
    public int hashCode() {
        return Objects.hash(deptno, dname, loc);
    }
}

②跳转到的servlet进行数据的收集

package com.bjpowernode.oa.web.action;

import com.bjpowernode.oa.bean.Dept;
import com.bjpowernode.oa.utils.DBUtil;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

/**
 * @Author:朗朗乾坤
 * @Package:com.bjpowernode.oa.web.action
 * @Project:JavaWeb
 * @name:DeptServlet
 * @Date:2022/11/28 10:39
 */
@WebServlet({"/dept/list"})
public class DeptServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取servlet path
        String servletPath = request.getServletPath();
        if ("/dept/list".equals(servletPath)){
            doList(request,response);
        }

    }

    /**
     *1、 连接数据库,查询所有的部门信息,然后跳转到jsp做页面展示
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    private void doList(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{

        // 再创建一个容器,用来存储部门
        ArrayList<Dept> depts = new ArrayList<>();

        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            // 连接数据库
            conn = DBUtil.getCoonetion();
            // 获取预编译的数据库操作对象
            String sql = "select deptno,dname,loc from dept";
            ps = conn.prepareStatement(sql);
            // 执行sql
           rs = ps.executeQuery();
           // 遍历查询结果集
            while (rs.next()) {
                // 取出数据
                String deptno = rs.getString("deptno");
                String dname = rs.getString("dname");
                String loc = rs.getString("loc");
                // 将零散的数据封装一个对象放进去
                Dept dept = new Dept();
                dept.setDeptno(deptno);
                dept.setDname(dname);
                dept.setLoc(loc);
                // 肯定不止一个对象,所以创建一个集合(容器),用来存储部门对象
                depts.add(dept);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(conn,ps,rs);
        }

        // 将集合放到请求域当中
        request.setAttribute("deptList",depts);

        // 转发(不要重定向)
        request.getRequestDispatcher("/list.jsp").forward(request,response);

    }
}

③通过转发的方式跳转到的另一个list.jsp,进行数据的展示

重点:对于for循环打印,这里实际上是拆分开了,但是转化为java代码还是一个完整的for循环;第一次见到这种输出方式,可能会比较不适应!

<%@ page import="com.bjpowernode.oa.bean.Dept" %>
<%@ page import="java.util.List" %>

<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>部门列表页面</title>
	</head>
	<body>

<script type="text/javascript">
	function del(dno){
		// 弹出确认框,用户点击确定,返回true,点击取消返回false
		var ok = window.confirm("亲,删了不可恢复哦!");
		if(ok){
			document.location.href = "<%=request.getContextPath()%>/dept/delete?deptno=" + dno;
		}
	}
</script>

		<h1 align="center">部门列表</h1>
		<hr >
		<table border="1px" align="center" width="50%">
			<tr>
				<th>序号</th>
				<th>部门编号</th>
				<th>部门名称</th>
				<th>操作</th>
			</tr>

			<%
				// 从request域当中取出集合
				// getAttribute取出来的是Object类型,这里进行了强制类型转换
				List<Dept> deptList = (List<Dept>)request.getAttribute("deptList");
				// 循环遍历
				int i =0;
				for(Dept dept:deptList){
			%>

			<tr>
				<td><%=++i%></td>
				<td><%=dept.getDeptno()%></td>
				<td><%=dept.getLoc()%></td>
				<td>
					<a href="javascript:void(0)" onclick="del(10)">删除</a>
					<a href="<%=request.getContextPath()%>/modify.jsp">修改</a>
					<a href="<%=request.getContextPath()%>/detail.jsp">详情</a>
				</td>
			</tr>

			<%
				}
			%>

		</table>
		
		<hr >
		<a href="<%=request.getContextPath()%>/add.jsp">新增部门</a>
		
	</body>
</html>

④思考: 如果只使用JSP这一个技术,能不能开发web应用?

①当然可以使用JSP来完成所有的功能。因为JSP就是Servlet,在JSP的<%%>里面写的代码就是在service方法当中的,所以在<%%>当中完全可以编写JDBC代码,连接数据库,查询数据,也可以在这个方法当中编写业务逻辑代码,处理业务都是可以的,所以使用单独的JSP开发web应用完全没问题。

②虽然JSP一个技术就可以完成web应用,但是不建议,还是建议采用servlet + jsp的方式进行开发;这样都能将各自的优点发挥出来。JSP就是做数据展示!Servlet就是做数据的收集!(JSP中编写的Java代码越少越好)一定要职责分明!

⑤思考: JSP文件的扩展名必须是xxx.jsp吗?

①jsp文件的扩展名是可以配置的,不是固定的。

②在CATALINA_HOME/conf/web.xml,在这个文件当中配置jsp文件的扩展名。

③xxx.jsp文件对于Tomcat来说,只是一个普通的文本文件,web容器会将xxx.jsp文件最终生成java程序,最终调用的是java对象相关的方法,真正执行的时候,和jsp文件没有关系。

④小窍门:如果JSP代码看不懂,建议把jsp翻译成java代码,就能看懂了!

<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jsp</url-pattern>
    <url-pattern>*.jspx</url-pattern>
</servlet-mapping>

(2)list.jsp 跳转到detail.jsp

①对list.jsp中的详情超链接路径进行更改;并把部门编号也传过去

<a href="<%=request.getContextPath()%>/detail.jsp">详情</a>
<!--修改为-->
<a href="<%=request.getContextPath()%>/dept/detail?deptno=<%=dept.getDeptno()%>">详情</a>

②跳转到servlet,根据deptno进行数据的收集

这里就和上面不同,上面我们是查询所有的数据,有很多组,需要先把数据放到对象里,再把对象放到集合里;而这里每次使根据depto编号进行查询,就一组数据,所以不需要集合!

 /**
     *2、 根据部门编号,获取部门的详细信息
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    private void doDetail(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{
        // 创建一个集合,用来存放数据
        Dept dept = new Dept();
        // 通过key获取value,获取部门标号
        String deptno = request.getParameter("deptno");
        // 根据部门编号获取部门信息,将部门信息封装成对象
        // 不需要集合,因为只有一个对象的数据
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            // 获取连接
            conn = DBUtil.getCoonetion();
            // 获取预编译的数据库操作对象
            String sql = "select dname,loc from dept where deptno = ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1,deptno);
            // 执行sql
            rs = ps.executeQuery();
            // 处理查询结果集,实际上就一条数据
            if (rs.next()){
                String dname = rs.getString("dname");
                String loc = rs.getString("loc");
                // 把数据封装成一个对象
                // Dept dept = new Dept(); 定义到这里,下面转发使用不了
                dept.setDeptno(deptno);
                dept.setDname(dname);
                dept.setLoc(loc);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(conn,ps,rs);
        }

        // 将封装的对象放到请求域当中
        request.setAttribute("deptList",dept);

        // 转发(不要重定向)
        request.getRequestDispatcher("/detail.jsp").forward(request,response);

    }

③通过转发的方式跳转到的另一个detail.jsp,进行数据的展示

<%@ page import="com.bjpowernode.oa.bean.Dept" %>
<%@page contentType="text/html;charset=UTF-8" %>


<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>部门详情</title>
	</head>
	<body>
		<h1>部门详情</h1>
		<hr >

		<%
			// 从request域当中取出数据,强制类型转换
			Dept dept = (Dept)request.getAttribute("deptList");
		%>

		部门编号:<%=dept.getDeptno()%> <br>
		部门名称:<%=dept.getDname()%><br>
		部门位置:<%=dept.getLoc()%><br>
		
		<input type="button" value="后退" onclick="window.history.back()"/>
	</body>
</html>

(3)list.jsp 跳转到 删除操作

①对list.jsp中的删除超链接路径进行更改;这里是使用一个回调函数进行路径的跳转

<a href="javascript:void(0)" onclick="del(10)">删除</a>
// 修改为
<a href="javascript:void(0)" onclick="del(<%=dept.getDeptno()%>)">删除</a>

// 回调函数如下,没有修改:
<script type="text/javascript">
    function del(dno) {
        // 弹出确认框,用户点击确定,返回true,点击取消返回false
        var ok = window.confirm("亲,删了不可恢复哦!");
        if (ok) {
            document.location.href = "<%=request.getContextPath()%>/dept/delete?deptno=" + dno;
        }
    }
</script>

②跳转到servlet,根据deptno进行数据的收集;并且再次跳转到/dept/list页面进行数据的展示,这里使用的是重定向,因为不涉及从域中存取数据,所以尽可能使用重定向!

/**
     *3、 根据部门编号,删除部门
      * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    private void doDel(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取部门编号
        String deptno = request.getParameter("deptno");
        // 连接数据库
        Connection conn = null;
        PreparedStatement ps = null;
        int count = 0;
        try {
            conn = DBUtil.getCoonetion();
            String sql = "delete from dept where deptno=?";
            ps = conn.prepareStatement(sql);
            ps.setString(1,deptno);
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBUtil.close(conn,ps,null);
        }

        if (count==1) {
            // 删除成功,重定向到list页面;因为这里没有想域中放入数据,所以使用重定向
            // 重定向是要加项目名的,动态获取
            String contextPath = request.getContextPath();
            response.sendRedirect(contextPath+"/dept/list");
        }
    }

(4)list.jsp 跳转到 add.jsp

①对list.jsp中的详新增超链接路径不要更改,因为需要一个提交的表单;从add.jsp这个表单中跳转到servlet

注: 这里是提交数据,所以应该使用post请求!

<!--list.jsp这里不需要更改-->
<a href="<%=request.getContextPath()%>/add.jsp">新增部门</a>

<!--需要更改的是add.jsp里面的路径-->
<form action="<%=request.getContextPath()%>/list.jsp" method="get">
<!--修改为-->
<form action="<%=request.getContextPath()%>/dept/add" method="post">

②add.jsp

<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>新增部门</title>
	</head>
	<body>
		<h1>新增部门</h1>
		<hr >
		<%--<form action="<%=request.getContextPath()%>/list.jsp" method="get">--%>
		<form action="<%=request.getContextPath()%>/dept/add" method="post">
			部门编号<input type="text" name="deptno"/><br>
			部门名称<input type="text" name="dname"/><br>
			部门位置<input type="text" name="loc"/><br>
			<input type="submit" value="新增"/><br>
		</form>
	</body>
</html>

③跳转到servlet,根据前端提交的数据,调用getParameter方法获取到后,进行数据的插入;然后再通过重定向/dept/list页面,进行数据的展示

/**
     *  4、根据前端提交的数据,新增部门
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    private void doAdd(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取部门的信息
        // 注意乱码问题(Tomcat10不会出现这个问题)
        request.setCharacterEncoding("UTF-8");
        String deptno = request.getParameter("deptno");
        String dname = request.getParameter("dname");
        String loc = request.getParameter("loc");

        // 连接数据库执行insert语句
        Connection conn = null;
        PreparedStatement ps = null;
        int count = 0;
        try {
            conn = DBUtil.getCoonetion();
            String sql = "insert into dept(deptno, dname, loc) values(?,?,?)";
            ps = conn.prepareStatement(sql);
            ps.setString(1, deptno);
            ps.setString(2, dname);
            ps.setString(3, loc);
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, null);
        }
        if (count == 1) {
            response.sendRedirect(request.getContextPath() + "/dept/list");
        }
    }

(5)list.jsp 跳转到 modify.jsp

思考:我们已经知道对于修改实际上有两次连接数据库的操作;第一次点击list页面的修改实际上就相当于查询;所以我们不妨就让 修改和详情 共享一个页面;然后在打一个标记;根据标记决定最终是跳转到detail.jsp还是modify.jsp

①修改list.jsp代码;两个走的是通过一个servlet(/dept/detail),有一个标记f

<a href="<%=request.getContextPath()%>/dept/detail?f=modify&deptno=<%=dept.getDeptno()%>">修改</a>
<a href="<%=request.getContextPath()%>/dept/detail?f=detail&deptno=<%=dept.getDeptno()%>">详情</a>

②修改/dept/detail代码,就需要获取标记f,根据标记f来决定跳转的页面

// 方法1:获取这个标记,然后讨论
String f = request.getParameter("f");
if ("modify".equals(f)){
    request.getRequestDispatcher("/modify.jsp").forward(request,response);
}else if ("detail".equals(f)){
    request.getRequestDispatcher("/detail.jsp").forward(request,response);
}

// 方法2:进行拼串
String forward = "/"+request.getParameter("f")+".jsp";
request.getRequestDispatcher(forward).forward(request,response);

③对modify.jsp进行修改,也要修改成post请求

<%@ page import="com.bjpowernode.oa.bean.Dept" %>
<%@page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>修改部门</title>
	</head>
	<body>
		<h1>修改部门</h1>
		<hr >

		<%
			Dept dept = (Dept)request.getAttribute("dept");
		%>

		<!--<form action="<%=request.getContextPath()%>/list.jsp" method="get">
			部门编号<input type="text" name="deptno" value="20" readonly /><br>
			部门名称<input type="text" name="dname" value="销售部"/><br>
			部门位置<input type="text" name="loc" value="北京"/><br>
			<input type="submit" value="修改"/><br>
		</form>-->

		<form action="<%=request.getContextPath()%>/dept/modify" method="post">
			部门编号<input type="text" name="deptno" value="<%=dept.getDeptno()%>" readonly /><br>
			部门名称<input type="text" name="dname" value="<%=dept.getDname()%>"/><br>
			部门位置<input type="text" name="loc" value="<%=dept.getLoc()%>"/><br>
			<input type="submit" value="修改"/><br>
		</form>
	</body>
</html>

④跳转到/dept/modify,进行数据的更改

/**
     * 5、根据部门名称,进行修改
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    private void doModify(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 解决请求体的中文乱码问题。
        request.setCharacterEncoding("UTF-8");

        // 获取表单中的数据
        String deptno = request.getParameter("deptno");
        String dname = request.getParameter("dname");
        String loc = request.getParameter("loc");
        // 连接数据库执行更新语句
        Connection conn = null;
        PreparedStatement ps = null;
        int count = 0;
        try {
            conn = DBUtil.getCoonetion();
            String sql = "update dept set dname = ?, loc = ? where deptno = ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, dname);
            ps.setString(2, loc);
            ps.setString(3, deptno);
            count = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, ps, null);
        }

        if (count == 1) {
            // 更新成功
            response.sendRedirect(request.getContextPath() + "/dept/list");
        }
    }

在线举报