第一次程序开发设计作业
来源为同学的大作业
运行环境为idea
结果截图


代码改进:
新添了一个增删图片的功能
完整代码如下(只放了关键部分):
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");
%>
新闻详情
代码改善:
问题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
public static synchronized void writeFile(String filePath, List
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的大图,不仅占服务器空间,网页加载也慢,这优化也是个问题。

浙公网安备 33010602011771号