Servlet 执行原理和API 详情

2023-11-11

目录

1. Serlvet 运行原理

1.1 Tomcat 执行流程

 a. Tomcat 初始化流程

b. Tomcat处理请求流程

c. Servlet 中 service ⽅法的实现:

2. Servlet API详解

2.1 HttpServlet

2.1.1 核心方法

2.1.2 处理GET请求

2.2.3 处理POST请求

2.2 HttpServletRequest

2.2.1 核心方法

2.2.2 打印 Header 信息  

2.2.3 获取 GET 请求中的参数

2.2.4 获取 POST 请求中的参数

2.2.5 获取 JSON 格式参数 

3.HttpServletResponse

3.1 设置状态码  

 3.2 ⾃动刷新

3.3 重定向


1. Serlvet 运行原理

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("/hello")   //设置url映射   http://ip:port/hello
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置返回的类型和编码格式
        resp.setContentType("text/html; charset=UTF-8");
        //返回的数据
        resp.getWriter().println("<h1>你好.servlet.</h1>");
    }
}

输出:http://localhost:8080/first-servlet

 在 Servlet 的代码中并没有写 main ⽅法, 对应的 doGet 代码是如何被调⽤的呢?

1.1 Tomcat 执行流程

当浏览器给服务器发送请求的时候,Tomcat 作为 HTTP 服务器,可以接受到这个请求。

Tomcat 初始化 / 处理请求 :

 a. Tomcat 初始化流程

class Tomcat {
    // ⽤来存储所有的 Servlet 对象
    private List<Servlet> instanceList = new ArrayList<>();
    
    public static void main(String[] args) {
        new Tomcat().start();
   }
    public void start() {
           // 根据约定,读取 WEB-INF/web.xml 配置⽂件;
            // 并解析被 @WebServlet 注解修饰的类
            // 假定这个数组⾥就包含了我们解析到的所有被 @WebServlet 注解修饰的类.
        Class<Servlet>[] allServletClasses = ...;
            // 这⾥要做的的是实例化出所有的 Servlet 对象出来;
        for (Class<Servlet> cls : allServletClasses) {
            // 这⾥是利⽤ java 中的反射特性做的
            // 实际上还得涉及⼀个类的加载问题,因为我们的类字节码⽂件,是按照约定 的
            // ⽅式(全部在 WEB-INF/classes ⽂件夹下)存放的,所以 tomcat 内部是
            // 实现了⼀个⾃定义的类加载器(ClassLoader)⽤来负责这部分⼯作。
            Servlet ins = cls.newInstance();
            instanceList.add(ins);
       }
        // 调⽤每个 Servlet 对象的 init() ⽅法,这个⽅法在对象的⽣命中只会被调⽤这 ⼀次;
        for (Servlet ins : instanceList) {
            ins.init();
       }
        // 利⽤我们之前学过的知识,启动⼀个 HTTP 服务器
        // 并⽤线程池的⽅式分别处理每⼀个 Request
        ServerSocket serverSocket = new ServerSocket(8080);
        // 实际上 tomcat 不是⽤的固定线程池,这⾥只是为了说明情况
        ExecuteService pool = Executors.newFixedThreadPool(100);
        while (true) {
            Socket socket = ServerSocket.accept();
            // 每个请求都是⽤⼀个线程独⽴⽀持,这⾥体现了我们 Servlet 是运⾏在多线 程环境下的
            pool.execute(new Runnable() {
               doHttpRequest(socket);
       });
       }
        // 调⽤每个 Servlet 对象的 destroy() ⽅法,这个⽅法在对象的⽣命中只会被调⽤这⼀次;
        for (Servlet ins : instanceList) {
            ins.destroy();
       }
   }
}

1. Tomcat 的代码中内置了main方法,启动Tomcat时,就是从Tomcat 的 main 方法开始执行的。

2. 被 @WebServlet 注解修饰的类会在 Tomcat  启动的时候就会被获取到,并集中管理。

3. Tomcat 通过映射 的语法机制来创建 被 @WebServlet 注解修饰的类的实例。

4. 实例被创建完了之后, 会点调⽤其中的 init ⽅法进⾏初始化 。
5. 实例被销毁之前, 会调⽤其中的 destory ⽅法进⾏收尾⼯作。
6. Tomcat 内部也是通过 Socket API 进⾏⽹络通信.
7. Tomcat 为了能同时相应多个 HTTP 请求, 采取了多线程的⽅式实现. 因此 Servlet 是运⾏在 多线程环境下的。

b. Tomcat处理请求流程

class Tomcat {
    void doHttpRequest(Socket socket) {
        // 参照我们之前学习的 HTTP 服务器类似的原理,进⾏ HTTP 协议的请求解析,和响
应构建
        HttpServletRequest req = HttpServletRequest.parse(socket);
        HttpServletRequest resp = HttpServletRequest.build(socket);
        // 判断 URL 对应的⽂件是否可以直接在我们的根路径上找到对应的⽂件,如果找到, 就是静态内容
        // 直接使⽤我们学习过的 IO 进⾏内容输出
        if (file.exists()) {
            // 返回静态内容
            return;
       }
        // ⾛到这⾥的逻辑都是动态内容了
        // 根据我们在配置中说的,按照 URL -> servlet-name -> Servlet 对象的链条
        // 最终找到要处理本次请求的 Servlet 对象
        Servlet ins = findInstance(req.getURL());
        // 调⽤ Servlet 对象的 service ⽅法
        // 这⾥就会最终调⽤到我们⾃⼰写的 HttpServlet 的⼦类⾥的⽅法了
        try {
            ins.service(req, resp);    
       } catch (Exception e) {
            // 返回 500 ⻚⾯,表示服务器内部错误
       }
   }
}

 1. Tomcat 从 Socket 中读到的 HTTP 请求是⼀个字符串, 然后会按照 HTTP 协议的格式解析成⼀个 HttpServletRequest 对象。

2. Tomcat 会根据 URL 中的 path 判定这个请求是请求⼀个静态资源还是动态资源. 如果是静态资源, 直接找到对应的⽂件把⽂件的内容通过 Socket 返回. 如果是动态资源, 才会执⾏到 Servlet 的相关逻辑 。

3. Tomcat 会根据 URL 中的 Context Path 和 Servlet Path 确定要调⽤哪个 Servlet 实例的 service ⽅法。

4. 通过 service ⽅法, 就会进⼀步调⽤到我们之前写的 doGet 或者 doPost 。

c. Servlet 中 service ⽅法的实现:

class Servlet {
    public void service(HttpServletRequest req, HttpServletResponse resp) {
        String method = req.getMethod();
        if (method.equals("GET")) {
            doGet(req, resp);
       } else if (method.equals("POST")) {
            doPost(req, resp);
       } else if (method.equals("PUT")) {
            doPut(req, resp);
       } else if (method.equals("DELETE")) {
            doDelete(req, resp);
       }
       ......
   }
}
1. Servlet 的 service ⽅法内部会根据当前请求的⽅法, 决定调⽤其中的某个 doXXX ⽅法.
2. 在调⽤ doXXX ⽅法的时候, 就会触发 多态 机制, 从⽽执⾏到我们⾃⼰写的⼦类中的 doXXX ⽅法.

2. Servlet API详解

2.1 HttpServlet

 先创建类, 继承⾃ HttpServlet, 并重写其中的某些⽅法。

注意: HttpServlet 的实例只是在程序启动时创建⼀次. ⽽不是每次收到 HTTP 请求都重新创建实例.

2.1.1 核心方法

 实际开发过程中,主要重写 doXXX ⽅法, 很少会重写 init / destory / service 。

这些⽅法的调⽤时机, 就称为 "Servlet ⽣命周期". (也就是描述了⼀个 Servlet 实例从⽣到死的过程).

2.1.2 处理GET请求

@WebServlet("/hello")   //设置url映射   http://ip:port/hello
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置返回的类型和编码格式
        resp.setContentType("text/html; charset=UTF-8");
        //返回的数据
        resp.getWriter().println("<h1>你好.servlet.</h1>");
    }
}

数据提交的两种方式:

1. form 表单提交

2. ajax 提交

form 表单提交 :

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String result = "未知错误";
        // 1.得到参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        // 2.业务处理
        // 非空效验
        if (null != username && null != password && !username.equals("") && !password.equals("")) {
            if (username.equals("admin") && password.equals("admin")) {
                result = "恭喜:登录成功!";
            } else {
                result = "登录失败,用户名或密码输入错误,请检查!";
            }
        } else {
            result = "非法参数!";
        }

        resp.setContentType("text/html; charset=utf-8");

        // 3.将结果返回给前端
        resp.getWriter().write(result);
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户登录系统</title>
</head>
<body>
<form action="login" method="post">
    <div style="margin-top:50px;margin-left:40%;">
        <h1 style="padding-left:50px;">用户登录</h1>
            姓名:<input type="text" name="username">
        <p>
            密码:<input type="password" name="password">
        <p>
        <div style="padding-left:50px;">
            <input type="submit" value=" 提 交 "> &nbsp;&nbsp;&nbsp;
            <input type="reset" value=" 重 置 ">
        </div>
    </div>
</form>
</body>
</html>

 可以发现,点击“提交”之后,会从html页面变换到另外一个页面,并且不支持刷新。

 

 ajax 提交:

使⽤ Ajax 不需要刷新整个⻚⾯。

2.2.3 处理POST请求

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
    resp.setContentType("text/html; charset=utf-8");
    resp.getWriter().write("POST 响应");
}
@WebServlet("/hello")   //设置url映射   http://ip:port/hello
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

2.2 HttpServletRequest

2.2.1 核心方法

都是 "读" ⽅法, ⽽不是 "写" ⽅法,是服务器接收到的内容,不可以修改。  

2.2.2 打印 Header 信息  

@WebServlet("/myreq")
public class MyreqServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf-8");
        StringBuilder builder = new StringBuilder();
        // 得到请求的协议和版本号
        builder.append("协议:" + req.getProtocol() + "<br>");
        resp.getWriter().write(builder.toString());
    }
}

@WebServlet("/myreq")
public class MyreqServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf-8");
        StringBuilder builder = new StringBuilder();
        // 得到请求的协议和版本号
        builder.append("协议:" + req.getProtocol() + "<br>");
        // 得到请求的类型
        builder.append("Method:" + req.getMethod() + "<br>");
        resp.getWriter().write(builder.toString());
        // 得到 uri
        builder.append("URI:" + req.getRequestURI() + "<br>");
        builder.append("URL:" + req.getRequestURL() + "<br>");
        builder.append("ContextPath:" + req.getContextPath() + "<br>");
        builder.append("QueryString:" + req.getQueryString() + "<br>");
        //hr表示水平分隔符
        builder.append("<hr><h2>请求头</h2>");
        // 得到所有的请求类型(headerNames)和请求值
        Enumeration<String> headerNames = req.getHeaderNames();
        while (headerNames.hasMoreElements()) { // 判断还有没有 head name
            String headName = headerNames.nextElement();
            // 得到 head value
            String headValue = req.getHeader(headName);
            builder.append(headName + ": " + headValue + "<br>");
        }
        builder.append("<hr>");
        builder.append("参数:" + req.getParameter("name") + "<br>");
        resp.getWriter().write(builder.toString());
    }
}

 

2.2.3 获取 GET 请求中的参数

GET请求中的参数一般都是通过query string 传递给服务器的。

比如:http://localhost:8080/first-servlet/myreq?name=mysql&password=123

表示浏览器用过query string 给服务器传递了两个参数,nameId 和 passwordId,值分别是mysql,123 。在服务器端可以通过getParameter 来获取到参数的值。 

 此时说明服务器已经获取到客户端传递过来的参数 。getParameter 的返回值类型为 String. 必要的时候需要⼿动把 String 转成 int 。

 

 

jQuery.ajax({
            url:"login", // 设置请求地址
            type:"POST", // 设置请求方法类型
            contentType:"application/x-www-form-urlencoded; charset=utf-8", // 请求类型
            // dataType:"", // 响应的类型
            data:{"username":username.val(),"password":password.val()}, // 请求参数
            success:function(data){
                alert(data);
            }
        });

2.2.4 获取 POST 请求中的参数

POST 请求的参数⼀般通过 body 传递给服务器.
body 中的数据格式有很多种.。如果是采⽤ form 表单的形式, 仍然可以通过 getParameter 获取参数的值。

 

@WebServlet("/postParameter")
public class PostParameter extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse
resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf-8");
        String userId = req.getParameter("userId");
        String classId = req.getParameter("classId");
        resp.getWriter().write("userId: " + userId + ", " + "classId: " +
classId);
   }
}

 

<form action="postParameter" method="POST">
    <input type="text" name="userId">
    <input type="text" name="classId">
    <input type="submit" value="提交">
</form>

 

 

通过抓包可以看到, form 表单构造的 body 数据的格式为:

 

2.2.5 获取 JSON 格式参数

使⽤之前 getParameter 的⽅式获取不了 JSON 格式的数据。

@WebServlet("/postjson")
public class JsonPostServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置返回类型和编码
        resp.setContentType("text/html;charset=utf-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println("username" + ":" + username);
        System.out.println("password" + ":" + password);
        resp.getWriter().println("username" + username);
    }
}
输出:
http://localhost:8080/first-servlet
username:null
password:null

 

 

 

 使⽤ InputStream 获取 JSON 参数

@WebServlet("/postjson")
public class JsonPostServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //设置返回类型和编码
        resp.setContentType("text/html;charset=utf-8");
        //1. 得到数据流
        ServletInputStream inputStream = req.getInputStream();
        //2. 使用数组接受流信息
        byte[] bytes = new byte[req.getContentLength()];
        inputStream.read(bytes);
        //3. 将数组转换成字符串
        String result = new String(bytes,"utf-8");
        System.out.println(result);
        resp.getWriter().println(result);
    }
}

 

服务器拿到的 JSON 数据仍然是⼀个整体的 String 类型, 如果要想获取到 userId 和
classId 的具体值, 还需要搭配 JSON 库进⼀步解析。

 

public class App {
    public static void main(String[] args) throws JsonProcessingException {
        //1、创建一个json对象
        ObjectMapper objectMapper = new ObjectMapper();
        //2. 将对象转换成JSON字符串
        Student student = new Student();
        student.setId(1);
        student.setName("Java");
        student.setPassword("123");
        //将对象转换为string
        String result = objectMapper.writeValueAsString(student);
        System.out.println(result);
    }
}
@Data
class Student {
    private int id;
    private String name;
    private String password;
}

输出:
{"id":1,"name":"Java","password":"123"}
public class App {
    public static void main(String[] args) throws JsonProcessingException {
        //1、创建一个json对象
        ObjectMapper objectMapper = new ObjectMapper();
        //2.将JSON字符串转换为对象
        String jsonStr = "{\"id\":2,\"name\":\"MySQL\",\"password\":\"456\"}";
        //readValue(字符串,转换的目标类型)
        Student lisi = objectMapper.readValue(jsonStr,Student.class);
        System.out.println(lisi);
    }
}
@Data
@ToString
class Student {
    private int id;
    private String name;
    private String password;
}
输出:
Student(id=2, name=MySQL, password=456)

 

    //将对象转换为string
    String result = objectMapper.writeValueAsString(student);

        //2.将JSON字符串转换为对象
        String jsonStr = "{\"id\":2,\"name\":\"MySQL\",\"password\":\"456\"}";

Jackson 库的核⼼类为 ObjectMapper.
其中的 readValue ⽅法把⼀个 JSON 字符串转成 Java 对象.
其中的 writeValueAsString ⽅法把⼀个 Java 对象转成 JSON 格式字符串.

 

 

 

3.HttpServletResponse

响应对象是服务器要返回给浏览器的内容, 都 是 "写" ⽅法 。

 

3.1 设置状态码  

在浏览器通过参数指定要返回响应的状态码.
@WebServlet("/state")
public class StateServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int state = Integer.valueOf(req.getParameter("state"));
        if (state > 0) {
            resp.setStatus(state);
        } else {
            resp.setContentType("text/html; charset=utf-8");
            resp.getWriter().println("<h2>无效参数</h2>");
        }
    }
}

 

 3.2 ⾃动刷新

@WebServlet("/refresh")
public class RefreshServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //告诉浏览器1秒刷新一次
        resp.setHeader("Refresh", "1");
        resp.getWriter().println("" + LocalDateTime.now());
    }
}

 

看到浏览器每秒钟⾃动刷新⼀次.  

3.3 重定向

@WebServlet("/redirectServlet")
public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse
resp) throws ServletException, IOException {
        resp.sendRedirect("http://www.sogou.com");
   }
}

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Servlet 执行原理和API 详情 的相关文章

  • Mockito 在调用参数数量可变的方法时使用参数匹配器

    我试图在对具有可变数量参数的方法的调用中使用参数匹配器 Java 中的东西 没有成功 我的代码如下 我还将列出我尝试用来完成此工作的所有行 import static org mockito Mockito public class Met
  • 存根方法时出现 InvalidUseOfMatchersException

    我有这个 TestNG 测试方法代码 InjectMocks private FilmeService filmeService new FilmeServiceImpl Mock private FilmeDAO filmeDao Bef
  • createImage(int width, int height) 的问题

    我有以下代码 作为游戏的一部分每 10 毫秒运行一次 private void gameRender if dbImage null createImage returns null if GraphicsEnvironment isHea
  • @RestController 没有 @ResponseBody 方法工作不正确

    我有以下控制器 RestController RequestMapping value base url public class MyController RequestMapping value child url method Req
  • “java.net.MalformedURLException:未找到协议”读取到 html 文件

    我收到一个错误 java net MalformedURLException Protocol not found 我想读取网络上的 HTML 文件 mainfest uses permission android name android
  • 如何在 Antlr4 中为零参数函数编写语法

    我的函数具有参数语法 如下面的词法分析器和解析器 MyFunctionsLexer g4 lexer grammar MyFunctionsLexer FUNCTION FUNCTION NAME A Za z0 9 DOT COMMA L
  • Java:在 eclipse 中导出到 .jar 文件

    我正在尝试将 Eclipse 中的程序导出到 jar 文件 在我的项目中 我添加了一些图片和 PDF s 当我导出到 jar 文件时 似乎只有main已编译并导出 我的意愿是如果可能的话将所有内容导出到 jar 文件 因为这样我想将其转换为
  • 在 Wildfly 中与 war 部署共享 util jar 文件

    假设我有一个名为 util jar 的 jar 文件 该 jar 文件主要包含 JPA 实体和一些 util 类 无 EJB 如何使这个 jar 可用于 Wildfly 中部署的所有 war 无需将 jar 放置在 war 的 WEB IN
  • Integer.parseInt("0x1F60A") 以 NumberformatException 结束

    我尝试从数据库中获取长字符串内的表情符号代码 格式如下 0x1F60A 所以我可以访问代码 但它将是String 起初 我尝试通过执行以下操作来转换变量tv setText beforeEmo getEmijoByUnicode int e
  • 如何在代理后面安装 Eclipse Neon

    对于 Neon Eclipse 附带了一个安装程序 我在安装程序中找不到任何配置菜单 我的java版本是 java version java version 1 8 0 72 Java TM SE Runtime Environment b
  • 生成的序列以 1 开头,而不是注释中设置的 1000

    我想请求一些有关 Hibernate 创建的数据库序列的帮助 我有这个注释 下面的代码 在我的实体类中 以便为合作伙伴表提供单独的序列 我希望序列以 1000 开头 因为我在部署期间使用 import sql 将测试数据插入数据库 并且我希
  • 在另一个模块中使用自定义 gradle 插件模块

    我正在开发一个自定义插件 我希望能够在稍后阶段将其部署到存储库 因此我为其创建了一个独立的模块 在对其进行任何正式的 TDD 之前 我想手动进行某些探索性测试 因此 我创建了一个使用给定插件的演示模块 到目前为止 我发现执行此操作的唯一方法
  • 如何避免 ArrayIndexOutOfBoundsException 或 IndexOutOfBoundsException? [复制]

    这个问题在这里已经有答案了 如果你的问题是我得到了java lang ArrayIndexOutOfBoundsException在我的代码中 我不明白为什么会发生这种情况 这意味着什么以及如何避免它 这应该是最全面的典范 https me
  • HashMap 值需要不可变吗?

    我知道 HashMap 中的键需要是不可变的 或者至少确保它们的哈希码 hashCode 不会改变或与另一个具有不同状态的对象发生冲突 但是 HashMap中存储的值是否需要与上面相同 为什么或者为什么不 这个想法是能够改变值 例如在其上调
  • 在 SWT/JFace RCP 应用程序中填充巨大的表

    您将如何在 SWT 表中显示大量行 巨大是指超过 20K 行 20 列的东西 不要问我为什么需要展示那么多数据 这不是重点 关键是如何让它尽可能快地工作 这样最终用户就不会厌倦等待 每行显示某个对象的实例 列是其属性 一些 我想使用 JFa
  • QuerySyntaxException:无法找到类

    我正在使用 hql 生成 JunctionManagementListDto 类的实际 Java 对象 但我最终在控制台上出现以下异常 org hibernate hql internal ast QuerySyntaxException
  • 如何在 Java 中创建接受多个值的单个注释

    我有一个名为 Retention RetentionPolicy SOURCE Target ElementType METHOD public interface JIRA The Key Bug number JIRA referenc
  • JMenu 中的文本居中

    好吧 我一直在网上寻找有关此问题的帮助 但我尝试的任何方法似乎都不起作用 我想让所有菜单文本都集中在菜单按钮上 当我使用setHorizontalTextPosition JMenu CENTER 没有变化 事实上 无论我使用什么常量 菜单
  • Java Swing:需要一个高质量的带有复选框的开发 JTree

    我一直在寻找一个 Tree 实现 其中包含复选框 其中 当您选择一个节点时 树中的所有后继节点都会被自动选择 当您取消选择一个节点时 树中其所有后继节点都会自动取消选择 当已经选择了父节点 并且从其后继之一中删除了选择时 节点颜色将发生变化
  • 在java中使用多个bufferedImage

    我正在 java 小程序中制作游戏 并且正在尝试优化我的代码以减少闪烁 我已经实现了双缓冲 因此我尝试使用另一个 BufferedImage 来存储不改变的游戏背景元素的图片 这是我的代码的相关部分 public class QuizApp

随机推荐

  • C++ algorithm 头文件下的常用函数详解

    6 9 algorithm 头文件下的常用函数 使用algorithm头文件 6 9 1 max min 和abs max x y 和min x y 分别返回x和y中的最大值和最小值 abs x 返回x的绝对值 注意浮点型的绝对值请用mat
  • java程序配置dns后超时_Android笔记之解决OkHttp解析dns超时时间无法设置的问题

    问题 使用OkHttp 设备切换路由后 访问网络出现长时间无响应 很久以后才抛出UnknownHostException 这明显不是我们想要的 我们设置的connectTimeout属性似乎对dns的解析不起作用 如何解决 我们先看看OkH
  • FreeRTOS软件定时器

    目录 说明 一 定时器简介 1 1 定时器 1 2 软件定时器 1 3 硬件定时器 1 4 FreeRTOS软件定时器 1 5 软件定时器服务任务作用 1 6 软件定时器的命令队列 1 7 软件定时器相关配置 1 8 单次定时器和周期定时器
  • 基础算法题——折线分割平面(规律)

    题目 测试平台 我们看到过很多直线分割平面的题目 今天的这个题目稍微有些变化 我们要求的是n条折线分割平面的最大数目 比如 一条折线可以将平面分成两部分 两条折线最多可以将平面分成7部分 具体如下所示 Input 输入数据的第一行是一个整数
  • C#泛型类的定义及使用

    C 语言中泛型类的定义与泛型方法类似 是在泛型类的名称后面加上
  • Android Studio怎么打包成APK

    1 确定软件版本 将项目切换到Project 打开app目录下的build gradle文件 versionCode是app的大版本好 为数值类型 默认为1 改成2 versionName是app的具体版本号 为际符串类型 默认为1 0 改
  • Qt--子线程访问主线程

    一 子线程访问主线程数据和方法 原文 Qt C 子线程访问主线程数据和方法 lccsuse 博客园 报错widgets must be creat in the GUI thread 子线程是不能访问GUI对象 主要 Widget cpp
  • 11.最小栈

    题目 思路 维护两个栈 一个栈正常push元素 另一个栈维护每个元素为栈顶元素时的最小栈元素值 stack1 push x val x lt minStack top x minStack top 题解 class MinStack sta
  • MySQL 中的时间戳和日期时间转换函数

    在平时开发中 经常会遇到一些时间范围的查询 比如查询近 7 天内注册的新用户 如果表中存储的是 timestamp 类型 那么开发时 查询数据可能看到的是一个整形的时间戳 不便于阅读 怎么能让查询的结果集中的时间显示正常可读的时间格式呢 答
  • 迭代器c++实现

    迭代器 Iterator 模式的定义 提供一个对象来顺序访问聚合对象中的一系列数据 而不暴露聚合对象的内部表示 class Iterator public Iterator Iterator virtual std string First
  • centos卸载MySQL8,吐血整理

    一 内存与线程 1 内存结构 内存是计算机的重要部件之一 它是外存与CPU进行沟通的桥梁 计算机中所有程序的运行都在内存中进行 内存性能的强弱影响计算机整体发挥的水平 JVM的内存结构规定Java程序在执行时内存的申请 划分 使用 回收的管
  • Java中wait和sleep方法的区别

    两者的区别 这两个方法来自不同的类分别是Thread和Object 最主要是sleep方法没有释放锁 而wait方法释放了锁 使得其他线程可以使用同步控制块或者方法 锁代码块和方法锁 wait notify和notifyAll只能在同步控制
  • 探索Java8——用Optional取代null

    文章目录 为缺失值建模 采用防御式检查减少 NullPointerException Optional类入门 应用 Optional 的几种模式 为缺失值建模 假设你需要处理下面这样的嵌套对象 这是一个拥有汽车及汽车保险的客户 public
  • pyqt和ros结合使用接受相机和点云消息并展示(附代码)

    代码是 ROS 节点的 Python QT脚本 用于订阅 turtle1 cmd vel tracking image 和 test pointcloud 话题 脚本首先通过 ps 命令检查是否已启动 ROS 主节点 如果没有则启动一个新的
  • Kafka事务提交位点失败

    记一次kafka事务提交失败 线上业务报错 2019 10 29 20 27 48 621 l fin ycb sync server1 toc pre ali dm org springframework kafka KafkaListe
  • geopandas安装方法

    依次按顺序安装 在这下载依赖包 https www lfd uci edu gohlke pythonlibs 然后逐个安装 1 安装gdal pip install C Users lenovo Downloads GDAL 3 4 3
  • ajax调用echarts,ajax和echarts第一次相遇

    ajax和echarts渲染基础 对于动态数据的展示 数据库内容的实时展示 如何能快速高校的在前端图表中展示呢 今天 小柯君带你简单体会一下ajax的神奇可妙之处 要加油啊 各位君 一 echarts简单案例 1 先导入你下载好的echar
  • 报错类型提示:HEAP CORRUPTION DETECTED:after Nomal block

    上次做实验遇到了这个报错 足足调了好久 最后上网查了才知道为什么 注释处的代码就原本发生错误的代码 原因是你使用了你没有调用的空间 然后你用delete回收的时候回收了你未调用的空间 所以报错
  • 小规模票表比对不通过_增值税小规模纳税人申报比对异常怎么办?这里有最新处理流程...

    小规模纳税人的申报比对异常如何提示 应该到哪个科 所 进行处理 该科 所 在哪里 赶紧往下看吧 猴嗨森 发送报表后 提示 一窗式比对不通过 怎么办 根据异常事项提供相关证明材料到主管税务机关办理 牛给力 猴嗨森 需要预约号处理小规模纳税人申
  • Servlet 执行原理和API 详情

    目录 1 Serlvet 运行原理 1 1 Tomcat 执行流程 a Tomcat 初始化流程 b Tomcat处理请求流程 c Servlet 中 service 法的实现 2 Servlet API详解 2 1 HttpServlet