【项目小结】优点分析

一、 个人博客系统

一)限制强制登录

  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.mzph.cn/news/216763.shtml

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

相关文章

ArkTS布局

布局 通过Row和Column容器来实现布局 通用属性 justifyContent 设置子元素在主轴方向的对齐格式 Column容器参数如下&#xff08;Row容器只是改变主轴方向&#xff0c;将每个图横过来理解即可&#xff09; alignItems 设置子元素在交叉轴方向的对齐格式 Row容器使用VerticalA…

【清晰明了】Jenkins邮件发送配置

自带邮件插件 首先要知道的是jenkins是自带邮件插件的&#xff0c;且不支持卸载。 下面开始配置自带邮件插件。 配置默认邮件管理员 系统管理 --> 系统配置&#xff0c;进行如下配置&#xff1a; 不配置管理员邮件地址报错如下 jakarta.mail.internet.AddressException:…

成绩统计(oj题)

一道考验细节的题 最后是&#xff1f;&#xff1a;运算符用错了 代码如下&#xff1a; #include<stdio.h> #include<string.h> typedef struct Grade{int num;int inv; }Grade; Grade tmp[10]; int n, m, g, interval[10] {0};int main(void) {scanf("%d%d…

SPRD Android 13 下拉状态栏菜单添加静音快捷键简单记录

SPRD Android 13 下拉状态栏菜单添加静音快捷键简单记录 需要修改文件具体修改补丁吐槽需要修改文件 frameworks/base/packages/SystemUI/res/values/config.xml frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java frameworks/base…

【Python】手把手教你用tkinter设计图书管理登录UI界面(四)

上一篇&#xff1a;【Python】手把手教你用tkinter设计图书管理登录UI界面&#xff08;三&#xff09;-CSDN博客 下一篇&#xff1a; 本文主要阐述完成“用户密码找回”&#xff0c;诸位且看我如何实现吧&#xff01; 为了方便使用“已注册用户数据库.txt”的数据&#xff0…

Windows 11安装xray

需要先安装python&#xff0c;我这里已经安装好了&#xff0c;在命令行里边使用python --version可以看到自己的python版本。 xray的下载网址为https://github.com/chaitin/xray/releases&#xff0c;我根据自己的笔记本电脑配置&#xff0c;选择下载xray_windows_amd64.exe.…

静态代理,JDK动态代理,CGLIB代理原理详解

学习代理前要对反射有一定的了解 代理&#xff1a; 代理是一种设计模式&#xff0c;代理模式是一种结构型设计模式&#xff0c;它允许通过创建一个代理对象来控制对另一个对象的访问。代理对象充当了客户端与真实对象之间的中介&#xff0c;它可以在客户端和真实对象之间添加…

MySQL笔记-第08章_聚合函数

视频链接&#xff1a;【MySQL数据库入门到大牛&#xff0c;mysql安装到优化&#xff0c;百科全书级&#xff0c;全网天花板】 文章目录 第08章_聚合函数1. 聚合函数介绍1.1 AVG和SUM函数1.2 MIN和MAX函数1.3 COUNT函数 2. GROUP BY2.1 基本使用2.2 使用多个列分组2.3 GROUP BY中…

现代雷达车载应用——第2章 汽车雷达系统原理 2.2节

经典著作&#xff0c;值得一读&#xff0c;英文原版下载链接【免费】ModernRadarforAutomotiveApplications资源-CSDN文库。 2.2 汽车雷达架构 从顶层来看&#xff0c;基本的汽车雷达由发射器&#xff0c;接收器和天线组成。图2.2给出了一种简化的单通道连续波雷达结构[2]。这…

Excel——TEXTJOIN函数实现某一列值相等时合并其他列

一、TEXTJOIN函数介绍 公式TEXTJOIN(分隔符, 忽略空白单元格, 字符串1…) 分隔符&#xff1a;文本字符串&#xff0c;或者为空&#xff0c;或用双引号引起来的一个或多个字符&#xff0c;或对有效文本字符串的引用。如果提供一个数字&#xff0c;则将被视为文本。 忽略空白单…

Python 神奇解码器:pyWhat 库全面指南

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在当今数字化的世界中&#xff0c;理解和处理文本数据是许多应用程序的关键任务。而PyWhat库作为一个用于处理文本的Python库&#xff0c;提供了强大的功能&#xff0c;帮助开发者在文本中识别和提取有意义的信息…

deepface:实现人脸的识别和分析

deepface介绍 deepface能够实现的功能 人脸检测&#xff1a;deepface 可以在图像中检测出人脸的位置&#xff0c;为后续的人脸识别任务提供基础。 人脸对齐&#xff1a;为了提高识别准确性&#xff0c;deepface 会将检测到的人脸进行对齐操作&#xff0c;消除姿态、光照和表…

青蛙跳台阶(C语言)

1.代码: 2.问题:青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级台阶。求该青蛙跳上一个n级的台阶总共有多少种跳法&#xff1f; 3.答案: 我们用递归方法来解题: 秉持着大事化小原则: 假设让青蛙跳上一个台阶,那么还有(n - 1)个台阶要跳 假设让青蛙跳上二个台阶,那么还…

包装类 和 初阶泛型(详解)

【本节目标】 1. 以能阅读 java 集合源码为目标学习泛型 2. 掌握包装类 3. 掌握泛型 1. 包装类 在Java中&#xff0c;由于基本类型不是继承自Object&#xff0c;为了在泛型代码中可以支持基本类型&#xff0c;Java给每个基本类型都对应了一个包装类型。 除了Integer和Charact…

二百一十六、Flume——Flume拓扑结构之负载均衡和故障转移的开发案例(亲测,附截图)

一、目的 对于Flume的负载均衡和故障转移拓扑结构&#xff0c;进行一个开发测试 二、负载均衡和故障转移 &#xff08;一&#xff09;结构含义 Flume支持使用将多个sink逻辑上分到一个sink组 &#xff08;二&#xff09;结构特征 sink组配合不同的SinkProcessor可以实现负…

SpringBoot--入门使用

目录 SpringBoot简介 什么是SpringBoot 相比Spring&#xff0c;SpringBoot的有哪些特点 SpringBoot入门使用 创建SpringBoot项目 配置项目名称 启动SpringBoot SpringBoot整合依赖&#xff0c;配置开发环境 SpringBoot整合jdbc SpringBoot整合mybatis 配置开启log日志…

隔离电源与非隔离式电源

开关电源 文章目录 开关电源前言一、它们之间的区别是什么&#xff1f;二、如何区分它们呢&#xff1f;三、隔离电源与非隔离电源的优缺点四、隔离电源与非隔离电源的选择总结 前言 在产品设计时&#xff0c;倘若没有考虑应用环境对电源隔离的要求&#xff0c;产品到了应用时就…

Linux服务器安装vim命令

1、查看是否安装vim命令 vim /etc/hosts2、检查系统中是否存在安装包 rpm -qa|grep vim2、 安装vim yum -y install vim*4、测试是否安装成功 vim /etc/hosts

linux交换分区管理SWAP

概念查看当前的交换分区&#xff1a;free 6.2.5 交换分区管理SWAP 6.2.5.1 概念 作用&#xff1a; ”提升“内存容量&#xff0c;防止OOM&#xff08;out of memory&#xff0c;内存溢出&#xff09;。 ​ 对应windows中的虚拟内存。 ​ 从功能上讲&#xff0c;交换分区主要是…

Java进阶 1-1 枚举

目录 枚举的基本特性 枚举类型中的自定义方法 switch语句中的枚举 编译器创建的values()方法 使用实现代替继承 构建工具&#xff1a;生成随机的枚举 组织枚举 EnumSet EnumMap 本笔记参考自&#xff1a; 《On Java 中文版》 枚举类型通过enum关键字定义&#xff0c;其…