【项目小结】优点分析

一、 个人博客系统

一)限制强制登录

  1. 问题:限制用户登录后才能进行相关操作
  2. 解决:
    1)前端:
    ① 写一个函数用于判断登录状态,如果返回的状态码是200就不进行任何操作,否则Ajax实现页面的跳转操作。
    ② 因为 登录限制及跳转 在很多页面中都使用,但是我们没必要进行重复性的工作,所以直接在前端代码中新建一个文件夹js,并新建文件 app.js 来存储这些重复的代码,以此来实现代码的复用。
    前端登录

2)后端:
① 重写doGet方法,获取当前会话并判断,如果session存在则继续从session中获取user,如果user不存在则返回403;只有session存在且user也存在才是登录状态。
② 如果用户未登录或者session过期,就会出现session存在但用户未登录的情况。
后端登录

二)列表页限制博客长度

  1. 问题:博客列表页展示的是摘要信息,而不是文章的所有内容,需要对展示的文章长度做限制。
  2. 获取到文章的长度,然后进行判断,如果大于规定长度就使用subString进行截断
 // 3. 直接查询博客列表 --博客列表页public List<Blog> selectAll() {// 链表用来存储blogList<Blog> blogs = new ArrayList<>();Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {// 1. 和数据库建立连接connection = DBUtil.getConnection();// 2. 构造sqlString sql = "select * from blog order by postTime desc";statement = connection.prepareStatement(sql);//  3. 执行sqlresultSet = statement.executeQuery();// 4. 遍历结果集合拿到结果(while)while (resultSet.next()) {Blog blog = new Blog();blog.setBlogId(resultSet.getInt("blogId"));blog.setTitle(resultSet.getString("title"));// blog.setContent(resultSet.getString("content"));// 进行内容截断作为摘要,避免博客列表页内容过长String content = resultSet.getString("content");if(content.length() > 100) {content = content.substring(0,100) + " ...";}blog.setContent(content);blog.setPostTime(resultSet.getTimestamp("postTime"));blog.setUserId(resultSet.getInt("userId"));blogs.add(blog);}} catch (SQLException throwables) {throwables.printStackTrace();} finally {// 释放资源一定不要忘记!!!DBUtil.close(connection,statement,null);}return blogs;}

三)删除文章做限制

  1. 问题:作者/登录用户只能删除自己的文章,不能删除别人的文章(暂时没有设置管理员的角色)
  2. 解决:校验当前登录用户就是文章作者,并且删除时将session中的user对象给移除并重新定位到login页面
 if(blog.getUserId() != user.getUserId()) {// 如果不一样,则说明作者与登录用户不是一个人// 直接返回403resp.setStatus(403);resp.setContentType("text/html; charset=utf8");resp.getWriter().write("抱歉 您没有权限删除别人的文章!");return;}
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取会话HttpSession session = req.getSession();if(session == null) {resp.setStatus(403);return;}// 直接将session中的user对象给删除就行session.removeAttribute("user");// 重定向到登录页面resp.sendRedirect("login.html");}
}

四)空指针异常提示

  1. 问题:如直接在url中输入博客id,此时如果该博客不存在则会报空指针异常
  2. 解决:如果该id不存在,给出友好提示(后端使用resp.getWriter().write()给出友好提示;在前端页面中定义一个div元素,用于显示后端输出的内容document)
// 2. 获取到blogIdString blogId = req.getParameter("blogId");if(blogId == null) {resp.setStatus(404);resp.setContentType("text/html; charset=utf8");resp.getWriter().write("当前删除的blogId有误!");return;}// 3. 查询出该blogId对应的Blog对象BlogDao blogDao = new BlogDao();Blog blog = blogDao.selectOne(Integer.parseInt(blogId));if(blog == null) {resp.setStatus(404);resp.setContentType("text/html; charset=utf8");resp.getWriter().write("当前删除的博客不存在! blogId="+blogId);return;}

五)时间格式化

  1. 问题:插入数据库中的数据经查询,将其转换为json字符串之后返回的是TimeStamp类型的,是时间戳的形式
// 从数据库中获取数据:
// executeQuery执行select的sql并将结果进行保存resultSet,遍历结果集合next()并使用getString等获取结果,使用封装的setTimeStamp等来获取到值
public Blog selectOne(int blogId) {Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {// 1. 和数据库建立连接connection = DBUtil.getConnection();// 2. 构造sqlString sql = "select * from blog where blogId = ?";statement = connection.prepareStatement(sql);statement.setInt(1,blogId);//  3. 执行sqlresultSet = statement.executeQuery();// 4. 遍历结果集合(if)if (resultSet.next()) {Blog blog = new Blog();blog.setBlogId(resultSet.getInt("blogId"));blog.setTitle(resultSet.getString("title"));blog.setContent(resultSet.getString("content"));blog.setPostTime(resultSet.getTimestamp("postTime"));blog.setUserId(resultSet.getInt("userId"));return blog;}} catch (SQLException throwables) {throwables.printStackTrace();} finally {// 释放资源一定不要忘记!!!DBUtil.close(connection,statement,resultSet);}return null;}
  1. 解决:修改getPostTime方法,使其返回值从TimeStamp变为String,然后又使用SimpleDateFormat函数进行格式化。
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.format(postTime);
// postTime是String类型

补充

  1. 浏览器访问到的是之前的结果,这是触发了浏览器的缓存。
    ① 理由:浏览器需要通过网络从远程服务器获取到当前的页面数据,可能比较耗时;此时为了提高效率,做法就是让浏览器把必要的数据进行缓存;下次访问就不必访问网络了,而是直接读取缓存。
    ② 解决:进行强制刷新保证数据从网络获取。

  2. 区分:location.href(完整路径) 和 location.seach(query string)
    location

  3. 后端302重定向

	// 返回302重定向resp.sendRedirect("blog_list.html");
  1. Ajax中把对象转成字符串
data: JSON.stringify(body)

二、 在线OJ

一)容错能力,如id不存在则友好提示

二)编译运行临时文件uuid

  1. 问题:
  2. 解决:
    1)获取当前工作路径
System.out.println(System.getProperty("user.dir")); 
// 获取当前工作路径
public Task() {// 使用UUID这个类就能生成一个UUIDWORK_DIR = "./tmp/" + UUID.randomUUID().toString() + "/";CLASS = "Solution";CODE = WORK_DIR + CLASS + ".java";COMPILE_ERROR = WORK_DIR + "compileError.txt";STDOUT = WORK_DIR + "stdout.txt";STDERR = WORK_DIR + "stderr.txt";}

三)黑名单扫描代码

  1. 简单方法:使用一个黑名单,把有危险代码的特征都放到黑名单中。在获取到用户提交的代码时,就查找一下看当前是否命中了黑名单,如果命中了就提示出错,不去编译执行。
  2. 实现:
 // 0. 进行安全性判断if (!checkCodeSecurity(question.getCode())) {System.out.println("用户提交了不安全的代码!");answer.setError(3);answer.setReason("您提交的代码可能会危害到服务器,禁止运行!");return answer;}// 1. 将question里的code写入到一个Solution.java文件中FileUtil.writeFile(CODE,question.getCode());
private boolean checkCodeSecurity(String code) {// 设定一个黑名单List<String> blackList = new ArrayList<>();// 防止提交的代码运行恶意程序blackList.add("Runtime");blackList.add("exec");// 禁止提交的代码读写文件blackList.add("java.io");// 禁止提交的代码访问网络blackList.add("java.net");// 进行校验for (String str: blackList) {int pos = code.indexOf(str);if(pos >= 0) {// 找到了恶意代码特征,就不安全,返回falsereturn false;}}// 遍历结束后还没有发现恶意代码特征,安全return true;}

难点:

  1. 题目详情直接从数据库中获取会发现题目都挤到一行中了。
    1)原因:数据库中对题目要求的描述都是使用\n来表示换行的,而HTML不识别\n, HTML中的换行是<br>标签
    2)解决:
    ① 让服务器返回的数据中,\n都替换成
    (在后端代码ProblemServlet.java中,获取到题目详情之后,使用replaceAll进行替换)
    ② 给页面的标签里套一层

    标签,
    标签中的内容是可以识别\n的

  2. 点击提交之后代码不能进行编译,查看服务器生成的临时文件发现提交过来的代码时编辑框的初始代码
    解决:为了查看codeEditor的哪个属性可以看到实时代码,就在console中使用dir(codeEditor)进行查看,发现使用value属性可以看到提交的实时代码。因此在构造请求的时候使用value来替换innerHTML。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/215916.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023/12/12作业

思维导图 作业&#xff1a; 成果图 代码 #include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { speechernew QTextToSpeech(this); ui->setupUi(this); //一直获取当前时间 idst…

如何通过上下滑动实现亮度和音量调节(ArkUI)

场景说明 在音视频应用中通常可以通过上下滑动来调节屏幕亮度和音量大小&#xff0c;本例即为大家介绍如何实现上述UI效果。 说明&#xff1a; 由于当前亮度和音量调节功能仅对系统应用开发&#xff0c;所以本例仅讲解UI效果的实现。 效果呈现 本例效果如下&#xff1a; 当在…

k8s-service 7

由控制器来完成集群的工作负载&#xff0c;service&#xff08;微服务&#xff09;是将工作负载的应用暴露出去&#xff0c;从而解决访问问题 作用&#xff1a;无论是在集群内还是集群外&#xff0c;都可以访问pod上的应用&#xff0c;其实现对集群内的应用pod自动发现和负载均…

关于核心转储和GDB调试的理解

Linux应用程序发生Segmentation fault段错误时&#xff0c;如何利用core dump文件定位错误呢&#xff1f; 在 Linux 系统中&#xff0c;常将“主内存”称为核心(core)&#xff0c;而核心映像(core image) 就是 “进程”(process)执行当时的内存内容。当进程发生错误或收到“信…

论文怎么改才能降低重复率

一、引言&#xff1a;智能工具助力&#xff0c;轻松降低论文重复率 论文的重复率是学术写作中的重要问题&#xff0c;如何有效降低重复率成为了许多研究者的关注焦点。如今&#xff0c;智能工具的发展为我们提供了更多选择。本文将介绍几种实用的智能工具&#xff0c;包括快码…

JAVA:深入了解Java中的Synchronized关键字

1、简述 在Java中&#xff0c;多线程编程是一项常见的任务&#xff0c;然而&#xff0c;它也伴随着一系列潜在的问题&#xff0c;比如竞态条件&#xff08;Race Condition&#xff09;和数据不一致性。为了解决这些问题&#xff0c;Java提供了一种同步机制&#xff0c;即synch…

【华为数据之道学习笔记】3-2 基础数据治理

基础数据用于对其他数据进行分类&#xff0c;在业界也称作参考数据。基础数据通常是静态的&#xff08;如国家、币种&#xff09;&#xff0c;一般在业务事件发生之前就已经预先定义。它的可选值数量有限&#xff0c;可以用作业务或IT的开关和判断条件。当基础数据的取值发生变…

5G下行链路中的MIMO

5G MIMO 影响5G MIMO配置的主要因素是天线的数量和层数UE和gNB有一些预定义的表来定义天线端口和层的数量&#xff0c;选择了特定的表&#xff0c;UE如何确定表中的哪一行用于gNB的每次传输DCI 1-1中该规定了Antenna port 和 层数DMRS 端口数表示正在使用的天线数量&#xff0…

波奇学Linux:Linux进程状态,进程优先级

编写一个程序模拟进程 查看进程状态 修改代码后发现进程状态为由S变成R R为运行态&#xff0c;S为阻塞态 第一次为S是因为调用了外设&#xff08;printf调用屏幕外设&#xff09;&#xff0c;实际上应该为R&#xff0c;S状态轮换&#xff0c;但是R太快了&#xff0c;所以每次…

中国区县人工智能企业数量,shp/excel格式,数据全,覆盖2010-2023年

基本信息. 数据名称: 中国区县人工智能企业数量 数据格式: Shpexcel 数据时间: 2010-2023年 数据几何类型: 面 数据坐标系: WGS84 数据来源&#xff1a;网络公开数据 数据字段&#xff1a;见【吧唧数据】www.bajidata.com 1a2023人工智能企业数量&#xff08;个&…

模块二——滑动窗口:3.无重复字符的最长子串

文章目录 题目描述算法原理解法⼀&#xff1a;暴⼒求解&#xff08;不会超时&#xff0c;可以通过&#xff09;解法二&#xff1a;滑动窗口 代码实现解法⼀&#xff1a;暴⼒求解(时间复杂度为O(N^2^)&#xff0c;空间复杂度为O(1))解法二&#xff1a;滑动窗口(时间复杂度为O(N)…

LeetCode-合并有序链表问题

合并两个有序链表 题目描述&#xff1a; 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 思路&#xff1a; 首先建立一个头节点方便后续操作&#xff0c;然后开始循环将两个链表的节点值进行比较&#xff0c;如果list1节…

hbuiler中使用npm安装datav

注&#xff1a;datav边框样式目前使用时&#xff1a;适用于网页&#xff0c;不适用于app 1、先安装node 安装、配置Node路径 2、为Node配置环境变量 3、在hbuilder的设置中填写node的路径 配置 4、打开cmd输入npm install jiaminghi/data-view 安装dataV&#xff0c;&…

MicroSD 卡 使用读卡器 读取速度测试

设备 - - 电脑为m.2固态硬盘 usb口为USB3.2 gen2接口(即支持1GB/s的接口) cpu: amd3600 测试方案1 直接MicroSD卡放入读卡器测试 38MB/s 从sd卡复制到本地C盘 测试方案2 MicroSD卡使用闪迪的SD卡套套上之后一起插入读卡器 76MB/s 从sd卡复制到本地C盘

uni-app应用设置 可以根据手机屏幕旋转进行 (横/竖) 屏切换

首先 我们打开项目的 manifest.json 在左侧导航栏中找到 源码视图 然后找到 app-plus 配置 在下面加上 "orientation": [//竖屏正方向"portrait-primary",//竖屏反方向"portrait-secondary",//横屏正方向"landscape-primary",//横屏…

Mybatis核心配置文件加载流程详解

Mybatis核心配置文件加载流程详解 本文将介绍MyBatis在配置文件加载的过程中&#xff0c;如何加载核心配置文件、如何解析映射文件中的SQL语句以及每条SQL语句如何与映射接口的方法进行关联。 映射配置文件 在介绍核心配置文件加载流程前&#xff0c;先给出一个简单的MyBati…

ROS gazebo 机器人仿真,环境与robot建模,添加相机 lidar,控制robot运动

b站上有一个非常好的ros教程234仿真之URDF_link标签简介-机器人系统仿真_哔哩哔哩_bilibili&#xff0c;推荐去看原视频。 视频教程的相关文档见&#xff1a;6.7.1 机器人运动控制以及里程计信息显示 Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程 本文对视频教程…

Docker入门指南:从基础到实践

在当今软件开发领域&#xff0c;Docker已经成为一种不可或缺的工具。通过将应用程序及其依赖项打包成轻量级的容器&#xff0c;Docker实现了开发、测试和部署的高度一致性。本文将深入研究Docker的基本概念&#xff0c;并通过详细的示例代码演示如何应用这些概念于实际场景中。…

基于FPGA的视频接口之高速IO(光纤)

简介 对于高速IO口配置光纤,现在目前大部分开发板都有配置,且也有说明,在此根据自己的工作经验以及对于各开发板的说明归纳 通过高速IO接口,以及硬件配置,可以实现对于光纤的收发功能,由于GTX的速率在500Mbs到10Gbps之间,但通道高速io可配置光纤10G硬件,物理通完成,则…

掌握 Python sympy 库的高级计算技巧

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com Sympy是Python中一个强大的符号计算库&#xff0c;为数学和科学计算提供了丰富的功能。本文将深入介绍Sympy库的各项功能&#xff0c;并提供丰富的示例代码&#xff0c;以帮助大家更好地理解和应用这一工具。 S…