java前后台交互从网络编程到SpringBoot

发布时间 2023-03-22 21:17:19作者: yfs1024

通过这片文章,想表达的是代码演变的过程,由繁到简

最原始的方法,通过网络编程、I/O流和多线程来实现:

package com.itheima;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

/*
 * 自定义web服务器
 */
public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(8080); // 监听指定端口
        System.out.println("server is running...");

        while (true){
            Socket sock = ss.accept();
            System.out.println("connected from " + sock.getRemoteSocketAddress());

            //开启线程处理请求
            Thread t = new Handler(sock);
            t.start();
        }
    }
}

class Handler extends Thread {
    Socket sock;

    public Handler(Socket sock) {
        this.sock = sock;
    }

    public void run() {
        try (InputStream input = this.sock.getInputStream(); OutputStream output = this.sock.getOutputStream()) {
                handle(input, output);
        } catch (Exception e) {
            try {
                this.sock.close();
            } catch (IOException ioe) {
            }
            System.out.println("client disconnected.");
        }
    }

    private void handle(InputStream input, OutputStream output) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8));

        // 读取HTTP请求:
        boolean requestOk = false;
        String first = reader.readLine();
        if (first.startsWith("GET / HTTP/1.")) {
            requestOk = true;
        }

        for (;;) {
            String header = reader.readLine();
            if (header.isEmpty()) { // 读取到空行时, HTTP Header读取完毕
                break;
            }
            System.out.println(header);
        }
        System.out.println(requestOk ? "Response OK" : "Response Error");

        if (!requestOk) {// 发送错误响应:
            writer.write("HTTP/1.0 404 Not Found\r\n");
            writer.write("Content-Length: 0\r\n");
            writer.write("\r\n");
            writer.flush();
        } else {  // 发送成功响应:
            //读取html文件,转换为字符串
            InputStream is = Server.class.getClassLoader().getResourceAsStream("html/a.html");
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            StringBuilder data = new StringBuilder();
            String line = null;
            while ((line = br.readLine()) != null){
                data.append(line);
            }
            br.close();
            int length = data.toString().getBytes(StandardCharsets.UTF_8).length;

            writer.write("HTTP/1.1 200 OK\r\n");
            writer.write("Connection: keep-alive\r\n");
            writer.write("Content-Type: text/html\r\n");
            writer.write("Content-Length: " + length + "\r\n");
            writer.write("\r\n"); // 空行标识Header和Body的分隔
            writer.write(data.toString());
            writer.flush();
        }
    }
}

后来Servlet对这些代码进行了封装,这个时候每一个类来处理一个请求。通过继承HttpServlet实现doGet和doPost方法,来实现业务处理

@WebServlet(name = "ServletConfigTest", urlPatterns = "/ServletConfigTest", initParams = {
        @WebInitParam(name = "name", value = "GRR") })
public class ServletConfigTest extends HttpServlet {

    private static final long serialVersionUID = 1L;
    private ServletConfig config;

    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

    public void init() throws ServletException {

    }

// 处理业务请求
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        String name = this.config.getInitParameter("name");
        response.getWriter().print(name);
    }


    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

后来SpringBoot直接封装。通过启动类的扫描,将当前包以及子包的所有带@Component,@Controller,@RestController,@Service,@Repository等注解都扫描设置为控制器,然后将类中的每个方法,访问路径做为key,方法名的全限定名作为value,生成一个map集合,当有请求的时候Spring通过访问路径,找到对应的方法进行处理。我想哈大概如下:

访问路径 方法的全限定名称(这样就可以通过发射来操作方法)
/crm/user/login com.yfs1024.controller.UserController#login
/crm/user/logout com.yfs1024.controller.UserController#logout
/admin/user/getAllGoods com.yfs1024.controller.admin.UserAdminController#getAllGoods

后来每一个方法来处理一个请求:

    /**
     * 分页条件查询轮播图
     *
     * @param carousel
     * @param page
     * @param rows
     * @return
     */
    @RequestMapping("/list")
    public Map<String, Object> list(Carousel carousel, @RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "rows", required = false) Integer rows) {
        Map<String, Object> resultMap = new HashMap<>(16);
        QueryWrapper<Carousel> carouselQueryWrapper = new QueryWrapper<>();
        if (carousel.getTitle() != null) {
            carouselQueryWrapper.like("title", carousel.getTitle());
        }
        carouselQueryWrapper.orderByAsc("sortNum");
        Page<Carousel> carouselPage = new Page<>(page, rows);
        List<Carousel> carouselList = carouselService.list(carouselQueryWrapper, carouselPage);
        Integer total = carouselService.getCount(carouselQueryWrapper);
        resultMap.put("rows", carouselList);
        resultMap.put("total", total);
        return resultMap;
    }