[Project Summary] Advantage Analysis

1. Personal blog system

1) Restrict forced login

  1. Problem: Users are restricted from logging in before they can perform relevant operations.
  2. Solution:
    1) Front-end:
    ① Write a function to determine the login status. If the returned status code is 200, nothing will be done. operation, otherwise Ajax implements the page jump operation.
    ② Because login restrictions and jumps are used in many pages, but we do not need to perform repetitive work, so we directly create a new folder js in the front-end code and create a new file app. js to store these repeated codes to achieve code reuse.
    Front-end login

2) Backend:
① Rewrite the doGet method, obtain the current session and judge, if the session exists, continue to obtain the user from the session, if the user does not exist, return 403; The login state is only when the session exists and the user also exists.
② If the user is not logged in or the session expires, there will be a situation where the session exists but the user is not logged in.
Backend login

2) Limit blog length on list page

  1. Problem: The blog list page displays summary information instead of all the content of the article. The length of the displayed article needs to be limited.
  2. Get the length of the article, and then judge it. If it is greater than the specified length, use subString to truncate it.
 // 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;
    }

3) Delete articles and impose restrictions

  1. Problem: Authors/logged-in users can only delete their own articles, not other people’s articles (there is no administrator role set yet)
  2. Solution: Verify that the currently logged in user is the author of the article, and when deleting, remove the user object in the session and relocate it to the login page.
 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");
    }
}

4) Null pointer exception prompt

  1. Problem: If you directly enter the blog ID in the URL, if the blog does not exist, a null pointer exception will be reported.
  2. Solution: If the id does not exist, give a friendly prompt (the backend uses resp.getWriter().write() to give a friendly prompt; define a div element in the front-end page to display the content document output by the backend)
// 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;
        }

5) Time formatting

  1. Question: After querying the data inserted into the database and converting it into a json string, the returned TimeStamp type is in the form of a 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. Solution: Modify the getPostTime method so that its return value changes from TimeStamp to String, and then use the SimpleDateFormat function to format it.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.format(postTime);
// postTime是String类型

Replenish

  1. The browser accesses the previous results, which triggers the browser's cache.
    ① Reason: The browser needs to obtain the current page data from the remote server through the network, which may be time-consuming; in order to improve efficiency at this time, the approach is to let the browser cache the necessary data; There is no need to access the network the next time you visit, but the cache is read directly.
    ② Solution: Perform forced refresh to ensure that the data is obtained from the network.

  2. Difference: location.href (full path) and location.seach (query string)
    location

  3. Backend 302 redirect

	// 返回302重定向
        resp.sendRedirect("blog_list.html");
  1. Convert object to string in Ajax
data: JSON.stringify(body)


2. Online OJ

1) Fault tolerance, friendly prompts if the id does not exist

2) Compile and run temporary file uuid

  1. question:
  2. Solution:
    1) Get the current working path
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";
    }

3) Blacklist scanning code

  1. Simple method: use a blacklist and put all the characteristics of dangerous code into the blacklist. When the code submitted by the user is obtained, a search is performed to see if it currently hits the blacklist. If it does, an error message is displayed and the code is not compiled and executed.
  2. accomplish:
 // 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;
    }

difficulty:

  1. If the question details are obtained directly from the database, you will find that the questions are squeezed into one row.
    1) Reason: The description of the question requirements in the database all uses \n to represent line breaks, but HTML does not recognize \n. Line breaks in HTML are <br> tags ② Add a layer to the page tag (in the back-end code ProblemServlet.java , after obtaining the question details, use replaceAll to replace) ① In the data returned by the server, \n is replaced with
    2) Solution:


    Label,
    The content in the tag is identifiable\n

  2. The code cannot be compiled after clicking submit. Check the temporary file generated by the server and find the initial code of the edit box when submitting the code
    Solution: In order to check which attributes of the codeEditor can be seen For the real-time code, use dir (codeEditor) in the console to view it, and find that you can use the value attribute to see the submitted real-time code. Therefore, use value to replace innerHTML when constructing the request.

Guess you like

Origin blog.csdn.net/weixin_54150521/article/details/134874033