项目实战——手写tomcat服务器

WebServerApplication

package com.webserver.core;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * WebServer主类
 */
public class WebServerApplication {
    private ServerSocket serverSocket;
    private String host;

    public WebServerApplication() {
        try {

            System.out.println("............................................. ");
            System.out.println("佛祖保佑                  永无BUG ");
            System.out.println(" 佛曰:                     ");
            System.out.println("写字楼里写字间,写字间里程序员;");
            System.out.println("程序人员写程序,又拿程序换酒钱。");
            System.out.println("酒醒只在网上坐,酒醉还来网下眠;");
            System.out.println("酒醉酒醒日复日,网上网下年复年。");
            System.out.println("但愿老死电脑间,不愿鞠躬老板前;");
            System.out.println("奔驰宝马贵者趣,公交自行程序员。");
            System.out.println("别人笑我忒疯癫,我笑自己命太贱;");
            System.out.println("不见满街漂亮妹,哪个归得程序员?");
            System.out.print("正在启动服务端,");
            serverSocket = new ServerSocket(8088);
            System.out.println("服务端启动完毕!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        try {
            while (true) {
                System.out.println("等待客户端链接...");
                Socket socket = serverSocket.accept();
                System.out.println("一个客户端链接了!");
                //启动一个线程处理与该客户端的交互
                ClientHandler handler = new ClientHandler(socket);
                Thread t = new Thread(handler);
                t.start();
                host = socket.getInetAddress().getHostAddress();
                System.out.println("用户" + host + "登录了");
            }

        } catch (IOException e) {
        }
    }

    public static void main(String[] args) {
        WebServerApplication application = new WebServerApplication();
        application.start();
    }
}

CilentHandler

package com.webserver.core;

import com.webserver.http.EmptyRequestException;
import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;

import java.io.*;
import java.net.Socket;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 处理一次与客户端的HTTP交互操作
 * 处理一次HTTP交互由三步完成:
 * 1:解析请求
 * 2:处理请求
 * 3:发送响应
 */
public class ClientHandler implements Runnable {
    private Socket socket;

    public ClientHandler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {

            /**
             *1解析请求
             */
            HttpServletRequest request = new HttpServletRequest(socket);
            //创建响应对象
            HttpServletResponse response = new HttpServletResponse(socket);
            /**
             *2处理请求
             */
            DispatcherServlet.getInstance().service(request, response);//单例模式
            /**
             *3发送响应
             */
            response.response();

        } catch (IOException e) {

        } catch (EmptyRequestException e) {
        } finally {
            //按照HTTP协议要求,一次交互后断开TCP连接
            try {
                socket.close();
            } catch (IOException e) {

            }
        }
    }
}

DispatcherServlet

package com.webserver.core;

import com.webserver.ArticleController.ArticController;
import com.webserver.controller.UserController;
import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;

/**
 * @Author Niukai
 * @Date 2022/7/14 14:26
 * DispatcherServlet是Spring MVC框架提供的一个核心类,用于和底层容器TOMACT整合使用。
 * 通过他使得程序员在写业务类时,无需再关注请求是如何调用到对应的业务处理类(某Controller)中
 * 对应的处理方法(被@RequestMapping注解标注的方法),其会根据请求自动调用。
 * 这里忽略了Tomcat和SpringMVC框架整合的细节,直接使用该类完成核心业务逻辑的刨析
 */
public class DispatcherServlet {
    private static DispatcherServlet dispatcherServlet;

    static {
        dispatcherServlet = new DispatcherServlet();
    }
    private DispatcherServlet(){}
   private static File rootDir;
   private static File staticDir;

    static {
        try {
            //定位到:target/classes
            rootDir = new File(ClientHandler.class.getClassLoader().getResource(".").toURI());
            //定位static目录
            staticDir = new File(rootDir, "static");
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //不能直接使用uri作为请求路径处理了,因为可能包含参数,而参数内容不是固定信息
        String path = request.getRequestURI();
        /*
        判断本次请求是否为请求某个业务
         */
        if("/regUser".equals(path)){
            UserController controller=new UserController();
            controller.reg(request,response);
        }
        else if ("/loginUser".equals(path)){
            UserController controller=new UserController();
            controller.loginUser(request,response);
        }
        else if ("/userList".equals(path)){
            UserController controller=new UserController();
            controller.userList(request,response);
        }else if ("/delete".equals(path)){
            UserController controller=new UserController();
            controller.delete(request,response);
        }else if ("/deletearticle".equals(path)){
            ArticController articController=new ArticController();
            articController.deletearticle(request,response);
        }
        else if ("/writeArticle".equals(path)){
            ArticController articController=new ArticController();
            articController.writeArticle(request,response);
        }
        else if ("/showAllArticle".equals(path)){
            ArticController articController=new ArticController();
            articController.showAllArticle(request,response);
        }

        else {
            File file = new File(staticDir, path);
            System.out.println("是否存在:" + file.exists());
            //判断是否存在,不存在则跳转到404.html
            if (file.isFile()) {
                response.setContentFile(file);
            } else {
                response.setStatusCode(404);
                response.setStatusReason("NotFound");
                response.setContentFile(new File(staticDir, "/root/404.html"));
            }
        }
    }

    public static DispatcherServlet getInstance() {
        return dispatcherServlet;
    }
}

HttpServletRequest

package com.webserver.http;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * @Author Niukai
 * @Date 2022/7/13 14:27
 * 请求对象
 * 该类的每一个实例用于表示浏览器发送过来的一个HTTP协议
 */
public class HttpServletRequest {
    private Socket socket;
    private String method;//请求方式
    private String uri;//抽象路径
    private String protocol;//协议版本


    private String requestURI;//保存uri中的请求部分("?"左侧的内容)
    private String queryString;//保存uri中的参数部分("?"右侧的内容)
    private Map<String, String> parameters = new HashMap<>();//保存每一组参数

    private Map<String, String> headers = new HashMap<>();//消息头相关信息

    public HttpServletRequest(Socket socket) throws IOException, EmptyRequestException {
        this.socket = socket;
        //1.1解析请求行
        parseRequestLine();
        //1.2解析消息头
        parseHeaders();
        // 1.3解析正文消息
        parseContent();
    }

    //解析请求行
    private void parseRequestLine() throws IOException, EmptyRequestException {

        String line = readLine();
        if (line.isEmpty()) {//如果请求行为空串,则说明本次为空请求
            throw new EmptyRequestException();
        }
        System.out.println("请求行:" + line);
        String[] data = line.split("\\s+");
        method = data[0];
        uri = data[1];
        protocol = data[2];
        parseURI();

    }

    //进一步解析uri
    private void parseURI() {
        String []data=uri.split("\\?");
        requestURI=data[0];
        if (data.length>1){
            queryString=data[1];
           parseParameters(queryString);
        }
    }
    //解析参数
    private void parseParameters(String line){

        //先将参数转换为中文
        try {
            line=URLDecoder.decode(line,"UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        String[] data=line.split("&");
        for (String para: data){
            String[] paras=para.split("=");
            parameters.put(paras[0],paras.length>1?paras[1]:"");
        }
    }
    //解析消息头
    private void parseHeaders() throws IOException {

        while (true) {
            String line = readLine();
            if (line.isEmpty()) {
                break;
            }
                /*
                    将每一个消息头按照": "(冒号+空格拆)分为消息头的名字和消息头的值
                    并以key,value的形式存入到headers中
                 */
            String[] data = line.split(":\\s");
            //将消息头的名字转换为全小写后存入headers,兼容性更好(浏览器发送的消息头无论大小写,只要拼写正确即可)
            headers.put(data[0].toLowerCase(Locale.ROOT), data[1].toLowerCase(Locale.ROOT));
        }
    }


    //解析消息正文
    private void parseContent() throws IOException {
        //判断本次请求方式是不是post请求
        if ("POST".equalsIgnoreCase(method)){//"post"
            //根据消息头Content-Length来确定正文的字节数量以便经行读取
           String contentLength=getHeader("Content-Length");
           if (contentLength!=null){
               //判断不为null的目的是确保有消息头Content-Length
               int length=Integer.parseInt(contentLength);
               System.out.println("正文长度"+length);
               byte []data=new byte[length];
               InputStream in=socket.getInputStream();
               in.read(data);
               //根据Content-Type来判断正文类型,并进行对应的处理
               String ContentType=getHeader("Content-Type");
               //分支判断不同的类型进行不同的处理
               if("application/x-www-form-urlencoded".equals(ContentType)){//判断类型是否为form表单不带附件的数据
                   String line=new String(data, StandardCharsets.ISO_8859_1);
                   System.out.println("正文内容"+line);
                   parseParameters(line);
               }
//               else if () {}扩展其他类型并进行对应的处理
           }

        }

    }


    private String readLine() throws IOException {
        InputStream is = socket.getInputStream();
        int d;
        char cur = 'a', pre = 'a';
        StringBuilder stringBuilder = new StringBuilder();
        while ((d = is.read()) != -1) {
            cur = (char) d;
            if (pre == 13 && cur == 10) {
                break;
            }
            stringBuilder.append(cur);
            pre = cur;
        }
        return stringBuilder.toString().trim();
    }


    public String getMethod() {
        return method;
    }

    public String getUri() {
        return uri;
    }

    public String getProtocol() {
        return protocol;
    }

    public String getHeader(String name) {
//        headers:
        return headers.get(name.toLowerCase(Locale.ROOT));

    }

    public String getRequestURI() {
        return requestURI;
    }

    public String getQueryString() {
        return queryString;
    }

    public String getParameter(String name) {
        return parameters.get(name);
    }



}

HttpServletResponse

package com.webserver.http;

import com.webserver.core.DispatcherServlet;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 响应对象
 * 该类的每一个实例表示HTTP协议规定的一个响应内容
 * 每个响应由三部分构成:
 * 状态行,响应头,响应正文
 */
public class HttpServletResponse {
    private Socket socket;

    //状态行的相关信息
    private int statusCode = 200;           //状态代码
    private String statusReason = "OK";     //状态描述

    //响应头相关信息
    private Map<String,String> headers = new HashMap<>();   //响应头

    //响应正文相关信息
    private File contentFile; //正文对应的实体文件
    private ByteArrayOutputStream baos;


    public HttpServletResponse(Socket socket){
        this.socket = socket;
    }

    /**
     * 将当前响应对象内容以标准的HTTP响应格式,发送给客户端(浏览器)
     */
    public void response() throws IOException {
        //发送前的准备工作
        sendBefore();
        //3.1发送状态行
        sendStatusLine();
        //3.2发送响应头
        sendHeaders();
        //3.3发送响应正文
        sendContent();
    }
    private void sendBefore(){
        //判断是否有动态数据存在
        if(baos!=null){
            addHeader("Content-Length",baos.size()+"");
        }
    }

    //发送状态行
    private void sendStatusLine() throws IOException {
        println("HTTP/1.1" + " " + statusCode + " " +statusReason);
    }
    //发送响应头
    private void sendHeaders() throws IOException {
        /*
            当发送响应头时,所有待发送的都应当都作为键值对存入了headers中
            headers:
            key                 value
            Content-Type        text/html
            Content-Length      245
            Server              WebServer
            ...                 ...
         */
        Set<Map.Entry<String,String>> entrySet = headers.entrySet();
        for(Map.Entry<String,String> e : entrySet){
            String name = e.getKey();
            String value = e.getValue();
            println(name + ": " + value);
        }

        //单独发送一组回车+换行表示响应头部分发送完了!
        println("");
    }
    //发送响应正文
    private void sendContent() throws IOException {
        if (baos!=null){//存在动态数据
            byte[]data=baos.toByteArray();
            OutputStream out=socket.getOutputStream();
            out.write(data);
        }
        else if(contentFile!=null) {
            try (
                    FileInputStream fis = new FileInputStream(contentFile);
            ) {
                OutputStream out = socket.getOutputStream();
                int len;
                byte[] data = new byte[1024 * 10];
                while ((len = fis.read(data)) != -1) {
                    out.write(data, 0, len);
                }
            }
        }
    }

    public void sendRedirect(String path){//path="/reg_success.html"
        statusCode = 302;
        statusReason = "Moved Temporarily";
        addHeader("Location",path);
    }


    /**
     * 向浏览器发送一行字符串(自动补充CR+LF)
     * @param line
     */
    private void println(String line) throws IOException {
        OutputStream out = socket.getOutputStream();
        out.write(line.getBytes(StandardCharsets.ISO_8859_1));
        out.write(13);//发送回车符
        out.write(10);//发送换行符
    }

    public int getStatusCode() {
        return statusCode;
    }

    public void setStatusCode(int statusCode) {
        this.statusCode = statusCode;
    }

    public String getStatusReason() {
        return statusReason;
    }

    public void setStatusReason(String statusReason) {
        this.statusReason = statusReason;
    }

    public File getContentFile() {
        return contentFile;
    }

    public void setContentFile(File contentFile) throws IOException {
        this.contentFile = contentFile;
        String contentType = Files.probeContentType(contentFile.toPath());
        //如果根据文件没有分析出Content-Type的值就不添加这个头了,HTTP协议规定服务端不发送这个头时由浏览器自行判断类型
        if(contentType!=null){
            addHeader("Content-Type",contentType);
        }
        addHeader("Content-Length",contentFile.length()+"");
    }
    public void addHeader(String name,String value){
        headers.put(name,value);
    }

    public OutputStream getOutputStream(){
        if(baos==null){
            baos=new ByteArrayOutputStream();
        }
        return baos;
    }
    public PrintWriter getWriter(){
        OutputStream out=getOutputStream();//低级流
        OutputStreamWriter osw=new OutputStreamWriter(out,StandardCharsets.UTF_8);
        BufferedWriter bw=new BufferedWriter(osw);
        PrintWriter pw=new PrintWriter(bw,true);
        return pw;
    }

    /**
     *添加响应头ContentType
     * @param  mine
     */
    public void setContentType(String mine){
        addHeader("Content-Type",mine);
    }

}

User

package com.webserver.entity;

import java.io.Serializable;

/**
 * @Author Niukai
 * @Date 2022/7/15 14:31
 */
public class User implements Serializable {
    static final long serialVersionUID = 42L;
    private String username;
    private String password;
    private String nickname;
    private int age;

    public User(){

    }

    public User(String username, String password, String nickname, int age) {
        this.username = username;
        this.password = password;
        this.nickname = nickname;
        this.age = age;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", nickname='" + nickname + '\'' +
                ", age=" + age +
                '}';
    }
}

UserController

package com.webserver.controller;

import com.webserver.entity.User;
import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 当前类负责处理与用户相关的操作
 */
public class UserController {
    private static File userDir;//该目录用于保存所有注册用户文件(一堆的.obj文件)

    static {
        userDir = new File("./users");
        if (!userDir.exists()) {//如果该目录不存在
            userDir.mkdirs();
        }
    }

    public void reg(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("开始处理用户注册!!!!!!!!!!!!!!!!!!!");
        //对应reg.html页面表单中<input name="username" type="text">
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String nickname = request.getParameter("nickname");
        String age = request.getParameter("age");
        System.out.println(username + "," + password + "," + nickname + "," + age);
        //对数据进行必要的验证工作
        if (username.isEmpty() || password.isEmpty() || nickname.isEmpty() || age.isEmpty() || !age.matches("[0-9]+")) {
            //如果如何上述情况,则直接响应给用户一个注册失败提示页面,告知信息输入有误。
            response.sendRedirect("/reg_info_error.html");
            return;
        }
        //处理注册
        //将年龄转换为int值
        int age_ = Integer.parseInt(age);
        User user = new User(username, password, nickname, age_);
        //参数1:当前File表示的文件所在的目录  参数2:当前文件的名字
        File userFile = new File(userDir, username + ".obj");
        if (userFile.exists()) {//文件已经存在说明该用户已经存在了!
            response.sendRedirect("/have_user.html");
            return;
        }
        try (
                FileOutputStream fos = new FileOutputStream(userFile);
                ObjectOutputStream oos = new ObjectOutputStream(fos);
        ) {
            oos.writeObject(user);
            //响应注册成功页面给浏览器
            response.sendRedirect("/reg_success.html");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void loginUser(HttpServletRequest request, HttpServletResponse response) {

        System.out.println("开始处理登录页面");
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        if (username.isEmpty() || password.isEmpty()) {
            response.sendRedirect("/login_Error.html");
        }

        File userFile = new File(userDir, username + ".obj");
        if (userFile.exists()) {
            try
                    (
                            FileInputStream fis = new FileInputStream(userFile);
                            ObjectInputStream ois = new ObjectInputStream(fis);
                    ) {
                User user = (User) ois.readObject();
                if (user.getUsername().equals(username) && user.getPassword().equals(password)) {
                    response.sendRedirect("/login_Success.html");
                }
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    public void userList(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("开始处理动态页面");//含有动态数据的页面叫动态页面
        //动态数据:由客户端新生成的数据
        //静态数据,提前写好的数据
        List<User> userList = new ArrayList<>();

        File[] subs = userDir.listFiles(f -> f.getName().endsWith(".obj"));
        for (File f : subs) {
            try (FileInputStream fis = new FileInputStream(f);
                 ObjectInputStream ois = new ObjectInputStream(fis);) {
                User user = (User) ois.readObject();
                userList.add(user);
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        response.setContentType("text/html;charset=utf-8");
        PrintWriter pw =response.getWriter();
        pw.println("<!DOCTYPE html>");
        pw.println("<html lang=\"en\">");
        pw.println("<head>");
        pw.println(" <meta charset=\"UTF-8\">");
        pw.println("<title>Title</title>");
        pw.println("</head>");
        pw.println("<body>");
        pw.println("<center>");
        pw.println("<h1>用户列表</h1>");
        pw.println("<table border=\"1\">");
        pw.println("<tr>");
        pw.println("<td>用户名</td>");
        pw.println("<td>密码</td>");
        pw.println("<td>昵称</td>");
        pw.println("<td>年龄</td>");
        pw.println("<td>操作</td>");
        pw.println("</tr>");
        for (User user : userList) {
            pw.println("<tr>");
            pw.println("<td>" + user.getUsername() + "</td>");
            pw.println("<td>" + user.getPassword() + "</td>");
            pw.println("<td>" + user.getNickname() + "</td>");
            pw.println("<td>" + user.getAge() + "</td>");
            pw.println("<td><a href='/delete?username=" + user.getUsername() + "'>删除</a></td>");
            pw.println("</tr>");
        }
        pw.println("</table>");
        pw.println("</center>");
        pw.println("</body>");
        pw.println("<html");
    }
    public void delete(HttpServletRequest request,HttpServletResponse response){
        String username=request.getParameter("username");
        File userFile=new File(userDir,username+".obj");
        if (userFile.exists()){
            userFile.delete();
        }
        response.sendRedirect("/userList");
    }

}

Article

package com.webserver.entity;

import java.io.Serializable;

/**
 * @Author Niukai
 * @Date 2022/7/19 9:46
 */
public class Article implements Serializable {
    static final long serialVersionUID = 42L;
    private String title;
    private String author;
    private String content;

    public Article(){

    }
    public Article(String title, String author, String content) {
        this.title = title;
        this.author = author;
        this.content = content;
    }



    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return "Article{" +
                "title='" + title + '\'' +
                ", author='" + author + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

ArticController

package com.webserver.ArticleController;

import com.webserver.entity.Article;

import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;
import sun.security.tools.keytool.Main;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author Niukai
 * @Date 2022/7/19 9:42
 * 发表文章的相关操作
 */
public class ArticController {
    private static File articleDir;

    static {
        articleDir = new File("./articles");
        if (!articleDir.exists()) {
            articleDir.mkdirs();
        }
    }

    public void writeArticle(HttpServletRequest request, HttpServletResponse response) {
        String title = request.getParameter("title");
        String author = request.getParameter("author");
        String content = request.getParameter("content");
        System.out.println(title + "," + author + "," + content);
        if (title == null || author == null || content == null || title.isEmpty() || author.isEmpty() || content.isEmpty()) {
            response.sendRedirect("/article_fail.html");
            return;
        }
        File articleFile = new File(articleDir, title + ".obj");
        if (articleFile.exists()) {
            //文件存在,说明是重复标题
            response.sendRedirect("/have_article.html");
            return;
        }
        Article article = new Article(title, author, content);
        try (
                FileOutputStream fos = new FileOutputStream(articleFile);
                ObjectOutputStream oos = new ObjectOutputStream(fos);
        ) {
            oos.writeObject(article);
            response.sendRedirect("/article_success.html");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void showAllArticle(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("处理文章列表请求");
        List<Article> articleList = new ArrayList<>();

        File[] subs = articleDir.listFiles(f -> f.getName().endsWith(".obj"));
        for (File f : subs) {
            try (
                    FileInputStream fis = new FileInputStream(f);
                    ObjectInputStream ois = new ObjectInputStream(fis);
            ) {
                Article article = (Article) ois.readObject();
                articleList.add(article);
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }

        }
        response.setContentType("text/html;charset=utf-8");
        PrintWriter pw = response.getWriter();
        pw.println("<!DOCTYPE html>");
        pw.println("<html lang=\"en\">");
        pw.println("<head>");
        pw.println(" <meta charset=\"UTF-8\">");
        pw.println("<title>Title</title>");
        pw.println("</head>");
        pw.println("<body>");
        pw.println("<center>");
        pw.println("<h1>文章列表</h1>");
        pw.println("<table border=\"1\">");
        pw.println("<tr>");
        pw.println("<td>标题</td>");
        pw.println("<td>作者</td>");
        pw.println("<td>操作</td>");
        pw.println("</tr>");
        for (Article article : articleList) {
            pw.println("<tr>");
            pw.println("<td>" + article.getTitle() + "</td>");
            pw.println("<td>" + article.getAuthor() + "</td>");
            pw.println("<td><a href='/deletearticle?title=" + article.getTitle() + "'>删除</a></td>");
            pw.println("</tr>");
        }
        pw.println("</table>");
        pw.println("</center>");
        pw.println("</body>");
        pw.println("<html");

    }

    public void deletearticle(HttpServletRequest request, HttpServletResponse response) {
        String title = request.getParameter("title");
        File articleFile = new File(articleDir, title + ".obj");
        if (articleFile.exists()) {
            articleFile.delete();
        }
        response.sendRedirect("/showAllArticle");
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛老师来巡山~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值