第一次程序开发设计作业

来源为同学的大作业
运行环境为idea
结果截图

image
image
代码改进:
新添了一个增删图片的功能
完整代码如下(只放了关键部分):
package com.news.servlet;

import com.news.dao.NewsDAO;
import com.news.model.News;
import com.news.model.User;
import com.news.util.IDUtil;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

@WebServlet("/addNews")
@MultipartConfig
public class AddNewsServlet extends HttpServlet {
private NewsDAO newsDAO = new NewsDAO();

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    HttpSession session = request.getSession();
    User user = (User) session.getAttribute("user");
    if (user == null) {
        response.sendRedirect("login.jsp");
        return;
    }

    String title = request.getParameter("title");
    String content = request.getParameter("content");
    String category = request.getParameter("category");

    // 处理图片上传
    Part part = request.getPart("image");
    String imagePath = "";
    if (part != null && part.getSize() > 0) {
        String uploadPath = getServletContext().getRealPath("/upload");
        File uploadDir = new File(uploadPath);
        if (!uploadDir.exists()) {
            uploadDir.mkdirs();
        }

        String fileName = System.currentTimeMillis() + "_" + part.getSubmittedFileName();
        String filePath = uploadPath + File.separator + fileName;
        part.write(filePath);
        imagePath = "upload/" + fileName;
    }

    String id = IDUtil.generateId();
    String author = user.getUsername();
    String createTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    String updateTime = createTime;
    int viewCount = 0;

    News news = new News(id, title, content, author, category, createTime, updateTime, viewCount, imagePath);
    newsDAO.addNews(news);

    response.sendRedirect("newsList");
}

}

package com.news.dao;

import com.news.model.News;
import com.news.util.FileUtil;

import java.util.List;
import java.util.stream.Collectors;

public class NewsDAO {
private static final String FILE_PATH = "data/news.txt";

public List<News> getAllNews() {
    return FileUtil.readFile(FILE_PATH, News::fromString);
}

public News getNewsById(String id) {
    List<News> newsList = getAllNews();
    for (News news : newsList) {
        if (news.getId().equals(id)) {
            return news;
        }
    }
    return null;
}

public List<News> getNewsByCategory(String category) {
    List<News> newsList = getAllNews();
    return newsList.stream()
            .filter(news -> news.getCategory().equals(category))
            .collect(Collectors.toList());
}

public List<News> searchNews(String keyword) {
    List<News> newsList = getAllNews();
    return newsList.stream()
            .filter(news -> news.getTitle().contains(keyword) || news.getContent().contains(keyword))
            .collect(Collectors.toList());
}

public void addNews(News news) {
    List<News> newsList = getAllNews();
    newsList.add(news);
    FileUtil.writeFile(FILE_PATH, newsList, News::toString);
}

public boolean updateNews(News news) {
    List<News> newsList = getAllNews();
    for (int i = 0; i < newsList.size(); i++) {
        if (newsList.get(i).getId().equals(news.getId())) {
            newsList.set(i, news);
            FileUtil.writeFile(FILE_PATH, newsList, News::toString);
            return true;
        }
    }
    return false;
}

public boolean deleteNews(String id) {
    List<News> newsList = getAllNews();
    for (int i = 0; i < newsList.size(); i++) {
        if (newsList.get(i).getId().equals(id)) {
            newsList.remove(i);
            FileUtil.writeFile(FILE_PATH, newsList, News::toString);
            return true;
        }
    }
    return false;
}

}

package com.news.servlet;

import com.news.dao.NewsDAO;
import com.news.model.News;

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;

@WebServlet("/newsDetail")
public class NewsDetailServlet extends HttpServlet {
private NewsDAO newsDAO = new NewsDAO();

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String id = request.getParameter("id");
    if (id == null || id.isEmpty()) {
        response.sendRedirect("newsList");
        return;
    }

    News news = newsDAO.getNewsById(id);
    if (news == null) {
        response.sendRedirect("newsList");
        return;
    }

    // 增加浏览量
    news.setViewCount(news.getViewCount() + 1);
    newsDAO.updateNews(news);

    request.setAttribute("news", news);
    request.getRequestDispatcher("news_detail.jsp").forward(request, response);
}

}

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="com.news.model.News" %>
<%
News news = (News) request.getAttribute("news");
%>

<%= news != null ? news.getTitle() : "新闻详情" %>

新闻详情

<% if (news != null) { %>

<%= news.getTitle() %>

作者: <%= news.getAuthor() %> | 分类: <%= news.getCategory() %> | 发布时间: <%= news.getCreateTime() %> | 更新时间: <%= news.getUpdateTime() %> | 浏览量: <%= news.getViewCount() %>
<% if (news.getImagePath() != null && !news.getImagePath().isEmpty()) { %> 新闻图片 <% } %>
<%= news.getContent().replace("\n", "
") %>
<% } else { %>

新闻不存在

<% } %>

代码改善:
问题1:内容包含逗号导致的数据解析错误:
当新闻标题或内容中包含逗号时,使用 String.split(",") 方法会导致数据字段被错误分割,例如:

  • 原数据: id,标题,内容,作者,...
  • 若内容为: 这是一条新闻,包含逗号,需要修复
  • 使用 split(",") 后会被分割为: [id, 标题, 这是一条新闻,包含逗号, 需要修复, 作者, ...]
  • 导致后续字段索引错误,无法正确解析数据

改进部分:
public static String[] safeSplit(String str, String delimiter, int expectedParts) {
String[] parts = new String[expectedParts];
int startIndex = 0;

for (int i = 0; i < expectedParts - 1; i++) {
    int delimiterIndex = str.indexOf(delimiter, startIndex);
    if (delimiterIndex == -1) {
        // 如果找不到足够的分隔符,剩余部分合并到最后一个字段
        parts[i] = str.substring(startIndex);
        for (int j = i + 1; j < expectedParts; j++) {
            parts[j] = "";
        }
        return parts;
    }
    parts[i] = str.substring(startIndex, delimiterIndex);
    startIndex = delimiterIndex + 1;
}

// 最后一个字段包含剩余所有内容,包括可能的分隔符
parts[expectedParts - 1] = str.substring(startIndex);
return parts;

}

问题2:文件读写的并发问题
当多个用户同时访问系统时,可能会出现并发读写文件的情况,导致:
数据覆盖:一个用户的写入操作覆盖另一个用户的写入操作
数据损坏:并发读写导致文件内容混乱
系统崩溃:极端情况下可能导致文件无法读取

改进部分:
在 FileUtil.java 中的所有文件操作方法添加 synchronized 关键字,确保同一时间只有一个线程可以访问文件:
public static synchronized List readFile(String filePath) { /* ... / }
public static synchronized void writeFile(String filePath, List lines) { /
... / }
public static synchronized void appendFile(String filePath, String line) { /
... / }
public static synchronized void deleteFile(String filePath) { /
... */ }
总结与难点:
文件上传处理懵圈
之前咱们的表单都是普通的 application/x-www-form-urlencoded 类型,加图片就得用 multipart/form-data ,这时候Servlet直接 request.getParameter() 根本拿不到值,当时我直接卡这儿了,不知道咋处理文件和普通字段共存的情况。
图片存哪儿?咋命名?
一开始想直接存到项目的 webapp 目录下,但又怕重启服务器或者重新部署时图片被覆盖;而且如果两个人同时上传同名图片,肯定会冲突,这命名规则也得好好想。
数据库咋关联图片?
之前的 news.txt 格式是 新闻ID,标题,内容,... ,加图片的话,字段咋加?加几个?是存绝对路径还是相对路径?会不会影响现有数据?
前端咋显示和编辑?
上传成功后,新闻列表和详情页咋正确显示图片?编辑新闻时,已有图片咋处理?是替换、删除还是保留?前端表单咋设计才能兼顾新上传和已有图片的情况?
图片太大咋整?
要是用户传个几MB的大图,不仅占服务器空间,网页加载也慢,这优化也是个问题。

posted @ 2026-03-10 12:23  2452417  阅读(6)  评论(0)    收藏  举报