【项目小结】优点分析

news2024/11/13 8:22:34

一、 个人博客系统

一)限制强制登录

  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() {
        // 链表用来存储blog
        List<Blog> blogs = new ArrayList<>();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            // 1. 和数据库建立连接
            connection = DBUtil.getConnection();
            // 2. 构造sql
            String sql = "select * from blog order by postTime desc";
            statement = connection.prepareStatement(sql);
            //  3. 执行sql
            resultSet = 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()) {
            // 如果不一样,则说明作者与登录用户不是一个人
            // 直接返回403
            resp.setStatus(403);
            resp.setContentType("text/html; charset=utf8");
            resp.getWriter().write("抱歉 您没有权限删除别人的文章!");
            return;
        }
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
    @Override
    protected 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. 获取到blogId
        String 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. 构造sql
          String sql = "select * from blog where blogId = ?";
          statement = connection.prepareStatement(sql);
          statement.setInt(1,blogId);
          //  3. 执行sql
          resultSet = 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这个类就能生成一个UUID
        WORK_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) {
                // 找到了恶意代码特征,就不安全,返回false
                return 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.coloradmin.cn/o/1305375.html

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

相关文章

Apollo配置发布原理解析

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化&#xff0c;文章内容兼具广度、深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于…

Windows下查看删除某一个端口号

背景&#xff1a;Java项目运行时&#xff0c;提示端口号被占用&#xff0c;然后就忘记之前是怎么处理的了&#xff0c;感觉还是像Linux中杀掉端口号就命令行的方式比较简单一些&#xff0c;然后就是各种搜索&#xff0c;记录一下 第一步&#xff1a;在cmd中查看该端口号是否被…

最强文生图跨模态大模型:Stable Diffusion

文章目录 一、概述二、Stable Diffusion v1 & v22.1 简介2.2 LAION-5B数据集2.3 CLIP条件控制模型2.4 模型训练 三、Stable Diffusion 发展3.1 图形界面3.1.1 Web UI3.1.2 Comfy UI 3.2 微调方法3.1 Lora 3.3 控制模型3.3.1 ControlNet 四、其他文生图模型4.1 DALL-E24.2 I…

Nginx的location匹配和rewrite重写

一、location匹配 常用的正则表达式 ^ &#xff1a;匹配输入字符串的起始位置 $ &#xff1a;匹配输入字符串的结束位置 * &#xff1a;匹配前面的字符零次或多次。如“ol*”能匹配“o”及“ol”、“oll”&#xff1a;匹配前面的字符一次或多次。如“ol”能匹配“ol”及“oll…

MySQL笔记-第14章_视图

视频链接&#xff1a;【MySQL数据库入门到大牛&#xff0c;mysql安装到优化&#xff0c;百科全书级&#xff0c;全网天花板】 文章目录 第14章_视图1. 常见的数据库对象2. 视图概述2.1 为什么使用视图&#xff1f;2.2 视图的理解 3. 创建视图3.1 创建单表视图3.2 创建多表联合视…

C++ exception类:C++标准异常的基类

C语言本身或者标准库抛出的异常都是 exception 的子类&#xff0c;称为标准异常&#xff08;Standard Exception&#xff09;。你可以通过下面的语句来捕获所有的标准异常&#xff1a; try{//可能抛出异常的语句}catch(exception &e){//处理异常的语句} 之所以使用引用&a…

GeoPandas实操:读取数据

GeoPandas 支持读取和写入多种地理空间数据格式&#xff0c;如 ESRI Shapefile、GeoJSON、GeoPackage 等&#xff0c;以及与其他 GIS 软件兼容的格式。 1. 读取数据 1.1. 读取ESRI Shapefile数据 ESRI Shapefile&#xff08;简称 Shapefile 或 .shp 文件&#xff09;是一种常…

Pandas中的Series(第1讲)

Pandas中的Series(第1讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔…

PHP操作ZIP之ZipArchive类以及如何避免生成压缩文件带有目录层级的问题

常用的方法 php ZipArchive可以说是php自带的一个函数了&#xff0c;他可对对文件进行压缩与解压缩处理&#xff0c;但是使用此类之前我们必须在php.ini中把extensionphp_zip.dll前面的分号有没有去掉&#xff0c;然后再重启Apache这样才能使用这个类库。 ziparchive 可选参数…

解决:Component name “index“ should always be multi-word

原因 要求组件名称以驼峰格式命名&#xff0c;自定义组件名称应该由多单纯组成&#xff0c;防止和html标签冲突&#xff0c;所以index.vue 会报错 解决 1、按照规则驼峰格式&#xff0c;如&#xff1a;appIndex.vue 2、若有.eslintrc.js文件&#xff0c;并在规则中(rules)关…

排序算法4:【快速排序】、查看每趟归并后的结果,定义一个全局变量,用来计数作为总趟数

一、快速排序——时间复杂度&#xff1a;、 最坏的情况 1、原理&#xff1a; 快速排序是通过多次比较和交换来实现排序&#xff0c;首先&#xff0c;先从数列中&#xff0c;任意选择一个数作为基准&#xff08;或叫分界值&#xff09;&#xff0c;比如&#xff0c;第一个数&a…

MySQL的事务以及springboot中如何使用事务

事务的四大特性&#xff1a; 概念&#xff1a; 事务 是一组操作的集合&#xff0c;它是不可分割的工作单元。事务会把所有操作作为一个整体&#xff0c;一起向系统提交或撤销操作请求&#xff0c;即这些操作要么同时成功&#xff0c;要么同时失败。 注意&#xff1a; 默认MySQ…

图解transformer中的自注意力机制(备忘)

注意力机制 在整个注意力过程中&#xff0c;模型会学习了三个权重:查询、键和值。查询、键和值的思想来源于信息检索系统。所以我们先理解数据库查询的思想。 假设有一个数据库&#xff0c;里面有所有一些作家和他们的书籍信息。现在我想读一些Rabindranath写的书&#xff1a…

网络编程----select 模型总结

为什么要使用select模型&#xff1f; 答&#xff1a;解决基本C/S模型中&#xff0c;accept()、recv()、send()阻塞的问题 select模型与C/S模型的不同点 C/S模型中accept()会阻塞一直傻等socket来链接select模型只解决accept()傻等的问题&#xff0c;不解决recv(),send()执行…

Android View闪烁动画AlphaAnimation,Kotlin

Android View闪烁动画AlphaAnimation&#xff0c;Kotlin private fun flickerAnimation(view: View?) {val animation: Animation AlphaAnimation(1f, 0f) //不透明到透明。animation.duration 500 // 1次过程时长。animation.interpolator LinearInterpolator() // 线性速…

一天搞定jmeter入门到入职全套教程之Jmeter分布式测试

随着并发量的增大&#xff0c;一台机器就不能满足需求了&#xff0c;所以我们采用分布式&#xff08;Master-Slaver&#xff09;的方案去执行高并发的测试 注意事项&#xff1a; Master机器一般我们不执测试&#xff0c;所以可以拿一台配置差些的机器&#xff0c;主要用来采集…

YOLOv8改进 | 2023主干篇 | 利用RT-DETR特征提取网络PPHGNetV2改进YOLOv8(超级轻量化精度更高)

一、本文介绍 本文给大家带来利用RT-DETR模型主干HGNet去替换YOLOv8的主干&#xff0c;RT-DETR是今年由百度推出的第一款实时的ViT模型&#xff0c;其在实时检测的领域上号称是打败了YOLO系列&#xff0c;其利用两个主干一个是HGNet一个是ResNet&#xff0c;其中HGNet就是我们…

养牛场北斗综合管理系统解决方案

1.系统架构 随着我国北斗卫星导航定位系统的快速发展和定位精度的持续不断提高&#xff0c;在牛身上穿戴定位终端后可以实现对牛的位置和温度的测量&#xff0c;在蜂窝网络正常的情况下&#xff0c;定位和温度数据通过蜂窝网络通信方式回传到监控云平台&#xff0c;在蜂窝网络缺…

使用docker编排容器

使用Dockerfile构建一个自定义的nginx 首先用docker拉一个nginx镜像 docker pull nginx拉取完成后&#xff0c;编辑一个Dockerfile文件 vim Dockerfile命令如下所示,FROM 后面跟的你的基础镜像&#xff0c;而run则是表示你构建镜像时需要执行的指令&#xff0c;下面的指令意…

mysql的ON DELETE CASCADE 和ON DELETE RESTRICT区别

​​ON DELETE CASCADE​​​ 和 ​​ON DELETE RESTRICT​​ 是 MySQL 中两种不同的外键约束级联操作。它们之间的主要区别在于当主表中的记录被删除时,子表中相关记录的处理方式。 ON DELETE CASCADE:当在主表中删除一条记录时,所有与之相关的子表中的匹配记录也会被自动删…