JSD-2204-WebServer(项目)-二维码-Day16

1.V22(版本)

实现动态数据的处理

以显示用户列表的需求为例:在首页上点击超链接,希望看到的页面上可以体现当前所有注册用户信息.
问题:该页面不能是实现准备好的页面,因为该页面上的数据会随着用户的操作(新注册用户,修改密码等)
不断变化.我们不可能实时的人为修改页面内容.因此我们需要实现当用户请求这个页面时,将现有的所有
用户信息获取到并生成一个html页面响应给用户.

静态资源:实现准备好的,数据内容(资源的2进制数据)不会改变的资源.
        例如:index.html页面,logo.png图片,或视频或gif图等等都属于静态资源.
动态资源:每次查看该资源时,都由程序临时生成的资源.
        例如:动态页面(此版本要实现的),验证码图片等

思路:
首页上点击超链接(该链接与form的action一样,由我们指定并由DispatcherServlet配合拦截),
之后DispatcherServlet拦截该请求并调用UserController生成动态页面的方法.
该方法中我们先将所有用户信息读取出来,并拼接一个html代码,拼接过程中将用户数据拼接进去.
然后将拼接好的页面发送给浏览器显示即可.

1.1项目目录

1.2Java文件

1.2.1UserController

package com.webserver.controller;

import com.webserver.entity.User;
import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;
import org.apache.log4j.Logger;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 处理与用户相关的业务操作
 */
public class UserController {
    private static Logger logger = Logger.getLogger(UserController.class);

    //表示users目录
    private static File userDir;
    static{
        userDir = new File("users");
        if(!userDir.exists()){
           userDir.mkdirs();
        }
    }

    /**
     * 生成展示所有用户信息的动态页面
     * @param request
     * @param response
     */
    public void showAllUser(HttpServletRequest request,HttpServletResponse response){
        /*
            1:通过读取users目录下所有的obj文件,进行反序列化
              得到所有的注册用户信息(若干的User对象)将他们存入一个List集合备用
            2:拼接一个HTML页面,并将所有用户信息拼接到table表格中用于展示给用户
            3:将拼接好的HTML代码作为正文给浏览器响应回去
         */
        //1
        List<User> userList = new ArrayList<>();
        /*
            1.1:通过File的listFiles方法,从userDir目录下获取所有的obj文件
                要使用文件过滤器
            1.2:遍历每一个obj文件,并利用对象流与文件流的连接,将obj文件中的
                User对象反序列化出来
            1.3:将反序列化的User对象存入userList集合中
         */
        //1.1
        File[] subs = userDir.listFiles(f->f.getName().endsWith(".obj"));
        //1.2
        for(File userFile : subs){
            try (
                    FileInputStream fis = new FileInputStream(userFile);
                    ObjectInputStream ois = new ObjectInputStream(fis);
            ){
                User user = (User)ois.readObject();
                //1.3
                userList.add(user);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        System.out.println(userList);

        //2将数据拼接到html生成页面
        File page =  new File("./userlist.html");
        try (
                PrintWriter pw = new PrintWriter(page);
        ){
            pw.println("<!DOCTYPE html>");
            pw.println("<html lang=\"en\">");
            pw.println("<head>");
            pw.println("<meta charset=\"UTF-8\">");
            pw.println("<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("</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("</tr>");
            }
            pw.println("</table>");
            pw.println("</center>");
            pw.println("</body>");
            pw.println("</html>");
            System.out.println("页面已生成");

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        //3
        response.setContentFile(page);


    }

    public void login(HttpServletRequest request, HttpServletResponse response){
        //1获取用户输入的登录信息
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if(username==null||password==null){
            response.sendRedirect("/myweb/login_info_error.html");
            return;
        }

        //2
        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.getPassword().equals(password)){//密码正确
                    //登录成功
                    response.sendRedirect("/myweb/login_success.html");
                    return;
                }
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        //如果程序走到这里,情况1:用户名没有输入正确,文件不存在
        //              情况2:用户名对了,但是密码不对
        response.sendRedirect("/myweb/login_fail.html");



    }

    public void reg(HttpServletRequest request, HttpServletResponse response){
        logger.info("开始处理注册");
        /*
            1:获取用户在注册页面上输入的注册信息
            2:将注册信息保存起来
            3:给用户回馈一个注册结果页面
         */
        //1
        //调用getParameter时传入的参数应当与页面上表单中输入框的名字一致(输入框name属性的值)
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String nickname = request.getParameter("nickname");
        String ageStr = request.getParameter("age");
        logger.info(username+","+password+","+nickname+","+ageStr);
        /*
            添加一个判断,要求:如果上述四个信息有null值或者年龄不是数字
            立刻给用户响应一个错误提示页面:reg_info_error.html
            该页面居中显示一行字:注册信息输入有误,请重新注册。

            正则表达式:[0-9]+
         */
        if(username==null||password==null||nickname==null||ageStr==null||
           !ageStr.matches("[0-9]+")){
            /*
               http://localhost:8088/myweb/reg?username=fancq&password=123456&nickname=fcq&age=22

               给浏览器发送的响应内容:
               HTTP/1.1 302 Moved Temporarily(CRLF)
               Location: /myweb/reg_info_error.html(CRLF)(CRLF)

               浏览器接收到该响应后,根据状态代码302得知服务器希望他自动再发起一次请求
               来请求指定的位置
               指定的位置是哪里?浏览器根据响应头Location得知位置
               此时得到的Location位置为:/myweb/reg_info_error.html

               由于浏览器之前的请求(发起注册):
               http://localhost:8088/myweb/reg?username=fancq&password=123456&nickname=fcq&age=22
               因此浏览器理解本次重新请求的路径就是:
               http://localhost:8088/myweb/reg_info_error.html
             */
            response.sendRedirect("/myweb/reg_info_error.html");
            return;
        }

        int age = Integer.parseInt(ageStr);
        System.out.println(username+","+password+","+nickname+","+age);

        //2
        User user = new User(username,password,nickname,age);
        File userFile = new File(userDir,username+".obj");
        /*
            判断重名,如果是已注册用户,则响应页面:have_user.html告知
            该页面居中显示一行字:该用户已存在,请重新注册。
         */
        if(userFile.exists()){//该文件存在则说明是重复用户
            response.sendRedirect("/myweb/have_user.html");
            return;
        }


        try (
                FileOutputStream fos = new FileOutputStream(userFile);
                ObjectOutputStream oos = new ObjectOutputStream(fos);
        ){
            //这里序列化的是注册用户信息,因此是user对象!!!!!!!!!!!!
            oos.writeObject(user);

            //3
            response.sendRedirect("/myweb/reg_success.html");
        } catch (IOException e) {
            e.printStackTrace();
            logger.error(e.getMessage(),e);
        }


    }

}

1.2.2DispatcherServlet

package com.webserver.core;

import com.webserver.controller.ArticleController;
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;
import java.nio.file.Files;

/**
 * 负责处理请求环节
 */
public class DispatcherServlet {
    private static File rootDir;
    private static File staticDir;

    static{
        try {
            rootDir = new File(
                    ClientHandler.class.getClassLoader()
                            .getResource(".").toURI()
            );
            staticDir = new File(rootDir,"static");
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    public void service(HttpServletRequest request, HttpServletResponse response){
        //不能再直接使用uri了,因为这里可能含有参数,而参数值是用户输入的,不是固定内容
//        String path = request.getUri();
        String path = request.getRequestURI();

        //根据请求路径判断是否为处理某个业务
        if("/myweb/reg".equals(path)){
            UserController controller = new UserController();
            controller.reg(request, response);

        }else if("/myweb/login".equals(path)){
            UserController controller = new UserController();
            controller.login(request, response);

        }else if("/myweb/writeArticle".equals(path)){
            ArticleController controller = new ArticleController();
            controller.writeArticle(request, response);

        }else if("/myweb/showAllUser".equals(path)){
            UserController controller = new UserController();
            controller.showAllUser(request, response);

        }else {
            File file = new File(staticDir, path);
            System.out.println("资源是否存在:" + file.exists());
            if (file.isFile()) {
                //将请求的实际文件设置到response的正文上等待响应
                response.setContentFile(file);
            } else {
                file = new File(staticDir, "/root/404.html");
                //将404内容设置到response上等待响应
                response.setStatusCode(404);
                response.setStatusReason("NotFound");
                response.setContentFile(file);
            }
        }
    }
}

1.3HTML文件

没有改动

2.V23(版本)

上一个版本中我们已经实现了动态页面。
问题:
将所有的用户记录读取出来并拼接好了html代码,但是需要现将数据写入文件userList.html,然后再
将该页面设置到response中去。等到response在发送响应式再从该文件中将数据读取出来后作为正文
响应给浏览器。
这里存在一次浪费,实际上没必要将生成的页面先写入文件再从文件读取出来,若直接将生成的html页面
数据存入response使其作为正文响应效率会高很多。
对此,我们要重构HttpServletResponse,使其可以为响应动态数据提供操作。

2.1项目目录

2.2Java文件

2.2.1UserController

package com.webserver.controller;

import com.webserver.entity.User;
import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;
import org.apache.log4j.Logger;

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

/**
 * 处理与用户相关的业务操作
 */
public class UserController {
    private static Logger logger = Logger.getLogger(UserController.class);

    //表示users目录
    private static File userDir;

    static {
        userDir = new File("users");
        if (!userDir.exists()) {
            userDir.mkdirs();
        }
    }

    /**
     * 生成展示所有用户信息的动态页面
     *
     * @param request
     * @param response
     */
    public void showAllUser(HttpServletRequest request, HttpServletResponse response) {
        /*
            1:通过读取users目录下所有的obj文件,进行反序列化
              得到所有的注册用户信息(若干的User对象)将他们存入一个List集合备用
            2:拼接一个HTML页面,并将所有用户信息拼接到table表格中用于展示给用户
            3:将拼接好的HTML代码作为正文给浏览器响应回去
         */
        //1
        List<User> userList = new ArrayList<>();
        /*
            1.1:通过File的listFiles方法,从userDir目录下获取所有的obj文件
                要使用文件过滤器
            1.2:遍历每一个obj文件,并利用对象流与文件流的连接,将obj文件中的
                User对象反序列化出来
            1.3:将反序列化的User对象存入userList集合中
         */
        //1.1
        File[] subs = userDir.listFiles(f -> f.getName().endsWith(".obj"));
        //1.2
        for (File userFile : subs) {
            try (
                    FileInputStream fis = new FileInputStream(userFile);
                    ObjectInputStream ois = new ObjectInputStream(fis);
            ) {
                User user = (User) ois.readObject();
                //1.3
                userList.add(user);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        System.out.println(userList);

        //2将数据拼接到html生成页面

        response.setContentType("text/html");

        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>");
        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("</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("</tr>");
        }
        pw.println("</table>");
        pw.println("</center>");
        pw.println("</body>");
        pw.println("</html>");
        System.out.println("页面已生成");





    }

    public void login(HttpServletRequest request, HttpServletResponse response) {
        //1获取用户输入的登录信息
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if (username == null || password == null) {
            response.sendRedirect("/myweb/login_info_error.html");
            return;
        }

        //2
        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.getPassword().equals(password)) {//密码正确
                    //登录成功
                    response.sendRedirect("/myweb/login_success.html");
                    return;
                }
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        //如果程序走到这里,情况1:用户名没有输入正确,文件不存在
        //              情况2:用户名对了,但是密码不对
        response.sendRedirect("/myweb/login_fail.html");


    }

    public void reg(HttpServletRequest request, HttpServletResponse response) {
        logger.info("开始处理注册");
        /*
            1:获取用户在注册页面上输入的注册信息
            2:将注册信息保存起来
            3:给用户回馈一个注册结果页面
         */
        //1
        //调用getParameter时传入的参数应当与页面上表单中输入框的名字一致(输入框name属性的值)
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String nickname = request.getParameter("nickname");
        String ageStr = request.getParameter("age");
        logger.info(username + "," + password + "," + nickname + "," + ageStr);
        /*
            添加一个判断,要求:如果上述四个信息有null值或者年龄不是数字
            立刻给用户响应一个错误提示页面:reg_info_error.html
            该页面居中显示一行字:注册信息输入有误,请重新注册。

            正则表达式:[0-9]+
         */
        if (username == null || password == null || nickname == null || ageStr == null ||
                !ageStr.matches("[0-9]+")) {
            /*
               http://localhost:8088/myweb/reg?username=fancq&password=123456&nickname=fcq&age=22

               给浏览器发送的响应内容:
               HTTP/1.1 302 Moved Temporarily(CRLF)
               Location: /myweb/reg_info_error.html(CRLF)(CRLF)

               浏览器接收到该响应后,根据状态代码302得知服务器希望他自动再发起一次请求
               来请求指定的位置
               指定的位置是哪里?浏览器根据响应头Location得知位置
               此时得到的Location位置为:/myweb/reg_info_error.html

               由于浏览器之前的请求(发起注册):
               http://localhost:8088/myweb/reg?username=fancq&password=123456&nickname=fcq&age=22
               因此浏览器理解本次重新请求的路径就是:
               http://localhost:8088/myweb/reg_info_error.html
             */
            response.sendRedirect("/myweb/reg_info_error.html");
            return;
        }

        int age = Integer.parseInt(ageStr);
        System.out.println(username + "," + password + "," + nickname + "," + age);

        //2
        User user = new User(username, password, nickname, age);
        File userFile = new File(userDir, username + ".obj");
        /*
            判断重名,如果是已注册用户,则响应页面:have_user.html告知
            该页面居中显示一行字:该用户已存在,请重新注册。
         */
        if (userFile.exists()) {//该文件存在则说明是重复用户
            response.sendRedirect("/myweb/have_user.html");
            return;
        }


        try (
                FileOutputStream fos = new FileOutputStream(userFile);
                ObjectOutputStream oos = new ObjectOutputStream(fos);
        ) {
            //这里序列化的是注册用户信息,因此是user对象!!!!!!!!!!!!
            oos.writeObject(user);

            //3
            response.sendRedirect("/myweb/reg_success.html");
        } catch (IOException e) {
            e.printStackTrace();
            logger.error(e.getMessage(), e);
        }


    }

}

2.2.2HttpServletResponse

package com.webserver.http;

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.Map.Entry;
import java.util.Set;

/**
 * 响应对象
 * 该类的每一个实例用于表示发送给客户端(浏览器)的一个HTTP响应内容
 * 每个响应由三部分构成:
 * 状态行,响应头,响应正文
 */
public class HttpServletResponse {
    private Socket socket;

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

    //响应头相关信息
    //key:响应头名字   value:响应头的值
    private Map<String,String> headers = new HashMap<>();


    //响应正文相关信息
    private File contentFile;//响应正文对应的实体文件
    private byte[] contentData;//以一组字节作为正文内容(通常动态数据使用)

    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){//如果baos不为null,则说明用过这个流写出过动态数据
            contentData = baos.toByteArray();//将内部的字节数组获取(动态数据)
            addHeader("Content-Length",contentData.length+"");
        }
    }


    //发送状态行
    private void sendStatusLine() throws IOException {
        println("HTTP/1.1" + " " + statusCode + " " + statusReason);
    }
    //发送响应头
    private void sendHeaders() throws IOException {
        /*
            headers
            KEY                 VALUE
            Content-Type        text/html
            Content-Length      2323
            ...                  ...
         */
        //遍历headers将所有的响应头发送给浏览器
        Set<Entry<String,String>> entrySet = headers.entrySet();
        for(Entry<String,String> e : entrySet){
            String key = e.getKey();
            String value = e.getValue();
            //println("Content-Type: text/html");
            println(key + ": " + value);
        }

        //单独发送回车+换行表示响应头部分发送完毕了
        println("");
    }
    //发送响应正文
    private void sendContent() throws IOException {
        if(contentData!=null){//是否有动态数据作为正文
            OutputStream out = socket.getOutputStream();
            out.write(contentData);

        }else if(contentFile!=null) {
            //try()意味着编译后有finally用于遍历流。所以这不违背try不能单独定义的原则
            try (
                    FileInputStream fis = new FileInputStream(contentFile);
            ) {
                OutputStream out = socket.getOutputStream();
                byte[] buf = new byte[1024 * 10];//10kb
                int len;//记录每次实际读取到的字节数
                while ((len = fis.read(buf)) != -1) {
                    out.write(buf, 0, len);
                }
            }
        }
    }




    private void println(String line) throws IOException {
        OutputStream out = socket.getOutputStream();
        byte[] data = line.getBytes(StandardCharsets.ISO_8859_1);
        out.write(data);//发送状态行内容
        out.write(13);//发送回车符
        out.write(10);//发送换行符
    }

    /**
     * 重定向到uri指定的路径
     * @param uri
     */
    public void sendRedirect(String uri){
        //1设置状态代码位302
        statusCode = 302;
        statusReason = "Moved Temporarily";

        //2添加必要的响应头Location指定浏览器再次请求的位置
        addHeader("Location",uri);
    }


    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) {
        this.contentFile = contentFile;
         /*
                根据正文文件类型来设置Content-Type用于告知浏览器该正文类型以便其理解.
                但是在HTTP协议中规定:如果发送响应时,不包含Content-Type响应头时,则是
                让浏览器自行理解正文类型.
             */
        try {
            //该方法会自动分析文件对应的Content-Type值,若无法识别会返回null
            //http://localhost:8088/TeduStore/index.html
                /*
                    比如:file表示的是 index.html 文件
                    该方法返回值为:"text/html"

                        file表示的是 jquery.js 文件
                    该方法那会的值为:"application/javascript"

                 */
            String type = Files.probeContentType(contentFile.toPath());
            if(type!=null) {
                addHeader("Content-Type", type);
            }
        } catch (IOException e) {
        }
        addHeader("Content-Length",contentFile.length()+"");


    }

    /**
     * 添加一个响应头
     * @param name
     * @param value
     */
    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(){
        /*
            进行流连接,创建一个PrintWrtier并最终连接到属性baos上
            将该PrintWriter返回给外界使用。
         */
        OutputStream out = getOutputStream();//baos
        OutputStreamWriter osw = new OutputStreamWriter(out,StandardCharsets.UTF_8);
        BufferedWriter bw = new BufferedWriter(osw);
        return new PrintWriter(bw,true);

//        return new PrintWriter(
//                new BufferedWriter(
//                        new OutputStreamWriter(
//                                getOutputStream(),StandardCharsets.UTF_8
//                        )
//                ),true
//        );
    }

    /**
     * 添加响应头Content-Type以及对应的值
     * @param mime
     */
    public void setContentType(String mime){
        addHeader("Content-Type",mime);
    }

}

2.3HTML文件

暂无改动上诉两个版本都是动态生成的页面

2.4运行流程

3.V24(版本)

参照生成用户列表的操作,独立实现展现所有文章列表的动态页面。
实现步骤:
1:在index.html上添加一个超链接,href="/myweb/showAllArticle"
2:在ArticleController中添加一个用于生成动态页面的方法:showAllArticle()
3:在DispatcherServlet上添加一个分支,如果路径是"/myweb/showAllArticle"则
  实例化ArticleController并调用showAllArticle处理

在ArticleController的showAllArticle方法中要做如下操作
1:将articles目录下所有的obj文件获取回来
2:遍历每一个obj文件并进行反序列化得到对应的Article对象并存入一个List集合备用
3:通过response设置Content-Type为text/html
  通过response获取PrintWriter,并拼接好动态页面,包含所有文章信息
  动态页面的表格中只需要两列,第一列展示文章标题,第二列展示作者

实现二维码功能

实现步骤:
1:在resources/static/myweb下新建一个页面:createQR.html
  页面上定义一个form表单。action="/myweb/createQR"
  并添加一个输入框,用于让用户输入二维码上要显示的内容。

2:在com.webserver.controller包下新建一个类:ToolsController
  该类用于处理如生成二维码,验证码等工具的业务类。
  在其中定义一个生成二维码的业务方法:createQR()

3:在DispatcherServlet的service方法上再添加一个分支,判断path的值是否为表单action的值"/myweb/createQR"
  如果是,则实例化ToolsController并调用其createQR()方法处理生成二维码的业务

4:ToolsController的createQR()方法中的实现步骤
  4.1:通过request.getParameter()获取表单中用户输入的二维码上要显示的内容。
  4.2:设置响应头Content-Type的值为:image/jpeg
  4.3 使用QRCodeUtil.encode()方法将二维码生成出来并写入到响应对象的正文上(response.getOutputStream())

如此一来,就完成了二维码的完整流程。最后可在index.html页面上添加一个超链接,访问到生成二维码的页面。

3.1项目目录

3.2Java文件

3.2.1ArticleController

package com.webserver.controller;

import com.webserver.core.ClientHandler;
import com.webserver.entity.Article;
import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;

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

public class ArticleController {
    private static File rootDir;
    private static File staticDir;

    //表示articles目录
    private static File articleDir;
    static{
        try {
            rootDir = new File(
                    ClientHandler.class.getClassLoader()
                            .getResource(".").toURI()
            );
            staticDir = new File(rootDir,"static");
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }

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


    public void writeArticle(HttpServletRequest request, HttpServletResponse response){
        //1获取表单数据
        String title = request.getParameter("title");
        String author = request.getParameter("author");
        String content = request.getParameter("content");
        if(title==null||author==null||content==null){
            File file = new File(staticDir,"/myweb/article_info_error.html");
            response.setContentFile(file);
            return;
        }

        //2写入文件
        File articleFile = new File(articleDir,title+".obj");
        if(articleFile.exists()){//文件存在,说明重复的标题,不能发表(需求过于严苛,后期数据库可通过ID避免该问题).
            File file = new File(staticDir,"/myweb/have_article.html");
            response.setContentFile(file);
            return;
        }

        Article article = new Article(title,author,content);
        try (
                FileOutputStream fos = new FileOutputStream(articleFile);
                ObjectOutputStream oos = new ObjectOutputStream(fos);
        ){
            oos.writeObject(article);
            File file = new File(staticDir,"/myweb/article_success.html");
            response.setContentFile(file);
        } catch (IOException e) {
            e.printStackTrace();
        }


        //3响应页面



    }
}

3.2.2ToolsController

这个需要到如一个包

将当前包添加到项目中 

 点击项目右面的+号

选择第二个Library 点进去

 选择QR这个是刚才创建的JAR包

点击这个就好了 

package com.webserver.controller;

import com.webserver.http.HttpServletRequest;
import com.webserver.http.HttpServletResponse;
import qrcode.QRCodeUtil;

import java.io.FileOutputStream;

public class ToolsController {

    public void createQR(HttpServletRequest request, HttpServletResponse response){
        String line = request.getParameter("content");
        try {
            response.setContentType("image/jpeg");
            QRCodeUtil.encode(
                    line,   //二维码上显示的文字
                    "./logo.jpg",   //二维码中间的logo图
                    response.getOutputStream(),//生成的二维码数据会通过该流写出
                    true);//是否压缩logo图片的尺寸

            System.out.println("二维码已生成");
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    public static void main(String[] args) {
        try {
            String line = "扫你妹!";
            //参数1:二维码上显示的文字,参数2:二维码图片生成的位置
//            QRCodeUtil.encode(line,"./qr.jpg");

            //参数1:二维码上显示的文字,参数2:二维码中间的logo图,
            //参数3:二维码生成的位置,参数4:是否压缩logo图片的尺寸
//            QRCodeUtil.encode(line,"./logo.jpg",
//                      "./qr.jpg",true);

            QRCodeUtil.encode(
                    line,   //二维码上显示的文字
                    "./logo.jpg",   //二维码中间的logo图
                    new FileOutputStream("./qr.jpg"),//生成的二维码数据会通过该流写出
                    true);//是否压缩logo图片的尺寸

            System.out.println("二维码已生成");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3.2.3DispatcherServlet

package com.webserver.core;

import com.webserver.controller.ArticleController;
import com.webserver.controller.ToolsController;
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;
import java.nio.file.Files;

/**
 * 负责处理请求环节
 */
public class DispatcherServlet {
    private static File rootDir;
    private static File staticDir;

    static{
        try {
            rootDir = new File(
                    ClientHandler.class.getClassLoader()
                            .getResource(".").toURI()
            );
            staticDir = new File(rootDir,"static");
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    public void service(HttpServletRequest request, HttpServletResponse response){
        //不能再直接使用uri了,因为这里可能含有参数,而参数值是用户输入的,不是固定内容
//        String path = request.getUri();
        String path = request.getRequestURI();

        //根据请求路径判断是否为处理某个业务
        if("/myweb/reg".equals(path)){
            UserController controller = new UserController();
            controller.reg(request, response);

        }else if("/myweb/login".equals(path)){
            UserController controller = new UserController();
            controller.login(request, response);

        }else if("/myweb/writeArticle".equals(path)){
            ArticleController controller = new ArticleController();
            controller.writeArticle(request, response);

        }else if("/myweb/showAllUser".equals(path)){
            UserController controller = new UserController();
            controller.showAllUser(request, response);

        }else if("/myweb/createQR".equals(path)){
            ToolsController controller = new ToolsController();
            controller.createQR(request, response);

        }else {
            File file = new File(staticDir, path);
            System.out.println("资源是否存在:" + file.exists());
            if (file.isFile()) {
                //将请求的实际文件设置到response的正文上等待响应
                response.setContentFile(file);
            } else {
                file = new File(staticDir, "/root/404.html");
                //将404内容设置到response上等待响应
                response.setStatusCode(404);
                response.setStatusReason("NotFound");
                response.setContentFile(file);
            }
        }
    }
}

3.3HTML文件

3.3.1createQR.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>二维码生成器</title>
</head>
<body>
    <center>
        <h1>二维码生成器</h1>
        <form action="/myweb/createQR" method="post">
            <table border="1">
                <tr>
                    <td>内容</td>
                    <td><input type="text" name="content"></td>
                </tr>
                <tr>
                    <td align="center" colspan="2"><input type="submit" value="生成"></td>
                </tr>
            </table>
        </form>
    </center>
</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值