Servlet教程

news2025/1/19 20:37:18

        在JavaEE平台上,处理TCP连接,解析HTTP协议这些底层工作统统扔给现成的Web服务器去做,我们只需要把自己的应用程序跑在Web服务器上。为了实现这一目的,JavaEE提供了Servlet API,我们使用Servlet API编写自己的Servlet来处理HTTP请求,Web服务器实现Servlet API接口

 

Servlet

public interface Servlet {
​
    // 根据 ServletConfig 来对 Servlet 进行初始化,只执行一次
    public void init(ServletConfig config) throws ServletException;
​
  
    // 获取 Servlet 传给 init() 的对象
    public ServletConfig getServletConfig();
​
   
    // 每次请求 Servlet 时,就会调用该方法
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;
​
​
    // 返回 Servlet 的一段描述
    public String getServletInfo();
​
  
    // 当卸载应用或者关闭 Servlet 容器时,调用该方法
    public void destroy();
}

GenericServlet

public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {
​
    private static final long serialVersionUID = 1L;
​
    private transient ServletConfig config;
​
    /**
     * Does nothing. All of the servlet initialization is done by one of the
     * <code>init</code> methods.
     */
    public GenericServlet() {
        // NOOP
    }
​
    /**
     * Called by the servlet container to indicate to a servlet that the servlet
     * is being taken out of service. See {@link Servlet#destroy}.
     */
    @Override
    public void destroy() {
        // NOOP by default
    }
​
    
    @Override
    public String getInitParameter(String name) {
        return getServletConfig().getInitParameter(name);
    }
​
   
    @Override
    public Enumeration<String> getInitParameterNames() {
        return getServletConfig().getInitParameterNames();
    }
​
    @Override
    public ServletConfig getServletConfig() {
        return config;
    }
​
    @Override
    public ServletContext getServletContext() {
        return getServletConfig().getServletContext();
    }
​
   
    @Override
    public String getServletInfo() {
        return "";
    }
​
   
    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
​
  
    // 提供给子类覆盖使用,如果选择覆盖上面的哪个方法,那么必须手动维护 ServletConfig 实例
    public void init() throws ServletException {
        // NOOP by default
    }
​
 
    public void log(String message) {
        getServletContext().log(getServletName() + ": " + message);
    }
​
 
    public void log(String message, Throwable t) {
        getServletContext().log(getServletName() + ": " + message, t);
    }
​
    /**
     * Called by the servlet container to allow the servlet to respond to a
     * request. See {@link Servlet#service}.
     * <p>
     * This method is declared abstract so subclasses, such as
     * <code>HttpServlet</code>, must override it.
     *
     * @param req
     *            the <code>ServletRequest</code> object that contains the
     *            client's request
     * @param res
     *            the <code>ServletResponse</code> object that will contain the
     *            servlet's response
     * @exception ServletException
     *                if an exception occurs that interferes with the servlet's
     *                normal operation occurred
     * @exception IOException
     *                if an input or output exception occurs
     */
    @Override
    public abstract void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;
​
   
    @Override
    public String getServletName() {
        return config.getServletName();
    }
}

HttpServlet

HttpServlet 抽象类是继承于 GenericServlet 抽象类而来的。使用 HttpServlet 抽象类时,还需要借助分别代表 Servlet请求和 Servlet 响应的 HttpServletRequest 和 HttpServletResponse 对象。

HttpServlet 抽象类覆盖了 GenericServlet 抽象类中的Service()方法,并且添加了一个自己独有的Service(HttpServletRequest request,HttpServletResponse)方法。

public abstract class HttpServlet extends GenericServlet {
​
    @Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {
​
        HttpServletRequest  request;
        HttpServletResponse response;
​
        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException(lStrings.getString("http.non_http"));
        }
        // 
        service(request, response);
    }
    
    
   protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
​
        String method = req.getMethod();
​
        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                } catch (IllegalArgumentException iae) {
                    // Invalid date header - proceed as if none was set
                    ifModifiedSince = -1;
                }
                if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }
​
        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);
​
        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
​
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
​
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
​
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
​
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
​
        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //
​
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
​
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }

HttpServlet 中的 service 方法把接收到的 ServletRequsest 类型的对象转换成了 HttpServletRequest 类型的对象,把ServletResponse 类型的对象转换成了 HttpServletResponse 类型的对象。之所以能够这样强制的转换,是因为在调用Servlet 的 Service 方法时,Servlet 容器总会传入一个 HttpServletRequest 对象和 HttpServletResponse 对象,预备使用HTTP。因此,转换类型当然不会出错了。

总之,HttpServlet有两个特性是GenericServlet所不具备的:

  • 不用覆盖 service 方法,而是覆盖 doGet 或者 doPost 方法。在少数情况,还会覆盖其他的5个方法。
  • 使用的是 HttpServletRequest 和 HttpServletResponse 对象

我们使用Servlet API时,并不直接与底层TCP交互,也不需要解析HTTP协议,因为HttpServletRequest和HttpServletResponse就已经封装好了请求和响应。以发送响应为例,我们只需要设置正确的响应类型,然后获取PrintWriter,写入响应即可。

ServletRequest

public interface ServletRequest {
    
    // 返回上下文指定对象(全局)
    public Object getAttribute(String name);
    
    // 返回请求主体的字节数
    public int getContentLength();
    
    // 返回主体的MIME类型 ex:text/html image/gif ...
    public String getContentType();
    
    // 返回请求参数的值
    public String getParameter(String name);
}

HttpServletRequest

HttpServletRequest 表示 Http 环境中的 Servlet 请求。它扩展于 javax.servlet.ServletRequest 接口,并添加了几个方法。

public interface HttpServletRequest extends ServletRequest {
    
    // 返回请求上下文的请求URI部分
    String getContextPath();
    
    // 返回一个cookie对象数组
    Cookie[] getCookies();
    
    // 返回指定HTTP标题的值
    String getHeader(String var1);
    
    // 返回生成这个请求HTTP的方法名称
    String getMethod();
    
    // 返回请求URL中的查询字符串
    String getQueryString();
    
    // 返回与这个请求相关的会话对象
    HttpSession getSession();
    
}

乱码问题

*在service中使用的编码解码方式默认为:ISO-8859-1编码*,但此编码并不支持中文,因此会出现乱码问题

// post 请求
request.setCharacterEncoding("UTF-8")
    
// get 请求
parameter = newString(parameter.getBytes("iso-8859-1"), "utf-8");

ServletResponse

public interface ServletResponse {
    
    public String getContentType();
    
    public ServletOutputStream getOutputStream() throws IOException;
    
    // 默认使用 ISO-8859-1 编码
    public PrintWriter getWriter() throws IOException;
    
}

HttpServletResponse

public interface HttpServletResponse extends ServletResponse {
    
    // 给这个响应添加一个cookie
    void addCookie(Cookie var1);
    
    // 给这个请求添加一个响应头
    void addHeader(String var1, String var2);
​
    // 发送一条响应码,讲浏览器跳转到指定的位置
    void sendRedirect(String var1) throws IOException;
    
    // 设置响应行的状态码
    void setStatus(int var1);
    
    // 获得字符流
    PrintWriter getWriter() throws IOException;
    
    // 获得字节流
    ServletOutputStream getOutputStream() throws IOException;
}

通过字符流的 write(String s) 方法可以将字符串设置到 response 缓冲区中,随后 Tomcat 会将 response 缓冲区中的内容组装成 Http 响应返回给浏览器端。

通过该字节流的 write(byte[] bytes) 可以向 response 缓冲区中写入字节,再由 Tomcat 服务器将字节内容组成 Http 响应返回给浏览器。

**注意:虽然response对象的getOutSream()和getWriter()方法都可以发送响应消息体,但是他们之间相互排斥,不可以同时使用,否则会发生异常。

乱码问题

response.setCharacterEncoding("utf-8");
​
// 通知浏览器使用 utf-8 解码
response.setHeader("Content-Type", "text/html;charset=utf-8")
    
// 该方法包含上面两个方法
response.setContentType("text/html;charset=utf-8")

 

ServletConfig

ServletConfig是指当前servlet在web.xml文件中的配置信息。开发者通过ServletConfig对象就可以得到当前servlet的初始化参数信息

public interface ServletConfig {
    
    public String getServletName();
​
    
    public ServletContext getServletContext();
​
    // 获取 Servlet 初始化参数
    public String getInitParameter(String name);
​
    // 获取 Servlet 初始化参数的名称
    public Enumeration<String> getInitParameterNames();
}

ServletContext

ServletContext是一个全局的储存信息的空间,服务器开始就存在,服务器关闭才释放

由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。公共聊天室就会用到它。

当web应用关闭、Tomcat关闭或者Web应用reload的时候,ServletContext对象会被销毁

获取 ServletContext

this.getServletContext();
this.getServletConfig.getServletContext()

 

ServletContext

public interface ServletContext {
 
    public Object getAttribute(String name);
    
    public void setAttribute(String name, Object object);
    
    public void removeAttribute(String name);
    
     public RequestDispatcher getRequestDispatcher(String path);
}

ServletContext应用

  • 多个Servlet可以通过ServletContext对象来实现数据间的共享

类似于Session,通过ServletContext对象我们也可以实现数据共享,但值得注意的是,Session是只能在一个客户端中共享数据,而ServletContext中的数据是在所有客户端中都可以实现数据共享的

  • 实现Servlet的请求转发
request.getRequestDispatcher("/url").forward(request, response);
​
this.getServletContext().getRequestDispather("/url").forward(request, response);
  • 获取Web应用的初始化参数
String name = this.getServletContext().getInitParameter("name");
  • 利用ServletContext对象读取资源文件(比如properties文件
// 文件在WebRoot文件夹下,即Web应用的根目录。这时候我们可以使用ServletContext来读取该资源文件
InputStream stream = this.getServletContext().getResourceAsStream("dbinfo.properties");
​
// 如果这个文件放在了src目录下,这时就不能用ServletContext来读取了,必须要使用类加载器去读取
InputStream stream = MyServlet.class.getClassLoader().getResourceAsStream("dbinfo.properties")

RequestDispatcher

RequestDispatcher 有一个特点,就是浏览器上显示的URL是最先请求的目标资源的URL,不会因为使用了forward、include方法而改变。因此forward和include的调用对于用户来说是透明的

public interface RequestDispatcher {
    
       public void forward(ServletRequest request, ServletResponse response)
            throws ServletException, IOException;
​
    public void include(ServletRequest request, ServletResponse response)
            throws ServletException, IOException;
}

forward

servlet2的response发送给客户端。而servlet1的response不会显示给用户

例如用户请求的是目标资源A,A接受到请求后,转发到B,真正产生响应数据是被转发的资源B,而A只是起个引导转发作用。浏览器的地址栏不会变,依然是A的URL。

注意事项:

1、在目标资源中调用forward方法时,必须保证此响应没有提交。也就是不要使用 ServletResponse 对象的输出流对象,因为即便你写入了数据到响应缓冲区,最后也会被清空,如果缓冲区数据被刷新提交(out.flush),还会抛出IllegalStateException异常。

2、对于forward方法传递的request对象:虽然我们从调用上看,好像是将request对象传递给转动的资源上去了,但是我发现目标资源使用的request对象和转发的资源使用的request对象不是同一个request对象,因为分别从这2个request中获取RequestURL,发现是不一样的。但是在目标资源request提取的Paramter 和 Attribute ,在转发后的资源的request对象中,依然都可以提取到,且是相同的。所以,二者只是在请求路径相关的属性上不同,其它API调用返回的都是一样的。

3、在forward语句的前后,都不应该有响应输出的语句,应该会被忽略

include

servlet2的response包含在(正在发送给客户端的)servlet1的response包中

注意事项:

1、被包含者(servlet2)不能设置ServletResponse的响应状态和响应头(否则并不会产生效果),因为这些都是包含者做的事,被包含者只需要产生响应数据解可以了。

2、不同于 forward中的request的传递特性:在被包含的资源中从request中获取请求路径相关的信息,发现依然是原始请求的路径,也就是浏览器地址栏相关的路径,也就是说被包含的资源获得的request对象的路径属性和原始请求资源的路径一样。其它的API调用也是一样的(Attribute 和Parameter)

sendReadirect

public interface HttpServletResponse extends ServletResponse {
    
    void sendRedirect(String var1) throws IOException;
}

sendReadirect() 方法和 forward() 都是用于请求转发的方法,转发给另外的资源为客户端服务。但二者有本质的区别

sendReadirect()方法原理:

  1. 客户端发送请求,Servlet1做出处理。
  2. Servlet1调用sendReadirect()方法,将客户端的请求 重新定位 到Servlet2。
  3. 客户端浏览器访问Servlet2.
  4. Servlet2对客户端浏览器做出响应。

forward()方法原理:

  1. 客户端发送请求,Servlet1做出处理。
  2. Servlet1调用sendReadirect()方法,将请求转发给Servlet2来处理请求,为客户端服务。
  3. Servlet2对客户端浏览器做出响应。

区别:

定位与转发

sendReadirect()方法是重新定位到另外一个资源来处理请求,URL会重新定位,让客户端重新访问另外一个资源。 forward()方法是转发到另外一个资源来处理请求。URL不会变化。隐藏了处理对象的变化。

处理请求的资源的范围

sendReadirect()方法可以跨WEB应用程序和服务器重新定位资源来处理请求。 forward()方法只能在应用程序内部转发。

参考文档

https://www.cnblogs.com/lulipro/p/7471987.html

Servlet请求转发 RequestDispatcher接口_qfs_v的博客-CSDN博客

Filter 

它是在 Servlet 2.3 规范中定义的,能够对 Servlet 容器传给 Web 资源的 request 对象和 response 对象进行检查和修改。

Filter 不是 Servlet,不能直接访问,它本身也不能生成 request 对象和 response 对象,它只能为 Web 资源提供以下过滤功能:

  • 在 Web 资源被访问前,检查 request 对象,修改请求头和请求正文,或对请求进行预处理操作。
  • 将请求传递到下一个过滤器或目标资源。
  • 在 Web 资源被访问后,检查 response 对象,修改响应头和响应正文。
public interface Filter {
​
    public default void init(FilterConfig filterConfig) throws ServletException {}
​
   
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;
​
   
    public default void destroy() {}
}

  1. 客户端请求访问容器内的 Web 资源。
  2. Servlet 容器接收请求,并针对本次请求分别创建一个 request 对象和 response 对象。
  3. 请求到达 Web 资源之前,先调用 Filter 的 doFilter() 方法,检查 request 对象,修改请求头和请求正文,或对请求进行预处理操作。
  4. 在 Filter 的 doFilter() 方法内,调用 FilterChain.doFilter() 方法,将请求传递给下一个过滤器或目标资源。
  5. 目标资源生成响应信息返回客户端之前,处理控制权会再次回到 Filter 的 doFilter() 方法,执行 FilterChain.doFilter() 后的语句,检查 response 对象,修改响应头和响应正文。
  6. 响应信息返回客户端。

Filter 的生命周期

Filter 的生命周期分为 3 个阶段:

  1. 初始化阶段:web应用程序启动时,web服务器将创建Filter的实例对象,并调用其init方法,完成对象的初始化。容器启动时,读取 web.xml 或 @WebFilter 的配置信息对所有的过滤器进行加载和实例化。
  2. 拦截和过滤阶段:当客户端请求访问 Web 资源时,Servlet 容器会根据 web.xml 或 @WebFilter 的过滤规则进行检查。当客户端请求的 URL 与过滤器映射匹配时,容器将该请求的 request 对象、response 对象以及 FilterChain 对象以参数的形式传递给 Filter 的 doFilter() 方法,并调用该方法对请求/响应进行拦截和过滤。可以执行多次
  3. 销毁阶段:Filter 对象创建后会驻留在内存中,直到容器关闭或应用被移除时销毁。销毁 Filter 对象之前,容器会先调用 destory() 方法,释放过滤器占用的资源。在 Filter 的生命周期内,destory() 只执行一次。

filterChain

public class FilterDemo1 implements Filter{
​
    /*
     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
    }
​
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        // TODO Auto-generated method stub
        System.out.println("我是FilterDemo1,客户端向Servlet发送的请求被我拦截到了");
        //对请求放行,进入下一个过滤器FilterDemo2
        chain.doFilter(request, response);
        System.out.println("我是FilterDemo1,Servlet向客户端发送的响应被我拦截到了");
    }
​
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }
​
}



public class FilterDemo2 implements Filter{
​
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
​
    }
​
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        // TODO Auto-generated method stub
        System.out.println("我是FilterDemo2,客户端向Servlet发送的请求被我拦截到了");
        //对请求放行,进入Servlet
        chain.doFilter(request, response);
        System.out.println("我是FilterDemo2,Servlet向客户端发送的响应被我拦截到了");
    }
​
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
​
    }
​
}
<filter>
    <filter-name>filterDemo1</filter-name>
    <filter-class>com.oracle.filter.FilterDemo1</filter-class>
</filter>
<filter>
    <filter-name>filterDemo2</filter-name>
    <filter-class>com.oracle.filter.FilterDemo2</filter-class>
</filter>
​
<filter-mapping>
    <filter-name>filterDemo1</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>filterDemo2</filter-name>
    <url-pattern>/*</url-pattern>
    <!-- /*是对所有的文件进行拦截 -->
</filter-mapping>

 分 析:当有多个过滤器对同一个请求进行拦截时,根据web.xml文件中的配置顺序,谁在前,先执行谁。当第 一过滤器拦截成功后,会执行doFilter方法,该方法中,调用chain.doFilter方法,会将该请求放行给下一个过滤器,依次执行,直到执行 到最后一个过滤器,当最后一个过滤器调用chain.doFilter方法时,请求会被放行给Servlet,当Servlet处理返回响应信息时,先返 回到最后执行的过滤器,继续执行该过滤器剩下的代码。依次返回,直到返回到第一个过滤器,最后返回给客户端。

ServletContextListener

监听 ServletContext 对象的生命周期,实际上就是监听 Web 应用的生命周期。

当Servlet 容器启动或终止Web 应用时,会触发ServletContextEvent 事件,该事件由ServletContextListener 来处理。

public interface ServletContextListener extends EventListener {
    
    // 当Servlet 容器启动Web 应用时调用该方法。在调用完该方法之后,容器再对Filter 初始化
    // 并且对那些在Web 应用启动时就需要被初始化的Servlet 进行初始化。
    default void contextInitialized(ServletContextEvent sce) {
    }
​
    // 当Servlet 容器终止Web 应用时调用该方法。在调用该方法之前,容器会先销毁所有的Servlet 和Filter 过滤器。 
    default void contextDestroyed(ServletContextEvent sce) {
    }
}

应用

在服务启动时,将数据库中的数据加载进内存,并将其赋值给一个属性名,其它的 Servlet 就可以通过 getAttribute 进行属性值的访问。

有如下两个步骤:

  1. ServletContext 对象是一个为整个 web 应用提供共享的内存,任何请求都可以访问里面的内容
  2. 如何实现在服务启动的时候就动态的加入到里面的内容:我们需要做的有:
    1. 实现 servletContextListerner 接口 并将要共享的通过 setAttribute ( name,data )方法提交到内存中去 ;
    2. 应用项目通过 getAttribute(name) 将数据取到

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/414744.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaWeb开发 —— 前端工程化

目录 一、前后端分离开发 二、YApi 三、前端工程化 1. 环境准备&#xff1a;vue-cli 2. Vue项目创建 四、Vue项目开发流程 一、前后端分离开发 ① 最早的前端开发就是实现页面&#xff0c;顶多再写写JS让页面可以有交互的特效。属于前后端未分离的时代。 早期前后端混合开…

Amazon 中国区配置 PingIdentity 身份集成实现 Redshift 数据库群集单点登录

无疑使用单点登录 (SSO)访问组织中的多种应用程序能够提升用户体验 。 如果您负责为 Amazon Redshift 启用 SSO&#xff0c;则可以使用 ADFS、PingIdentity、Okta、Azure AD 或其他基于 SAML 浏览器的身份提供程序设置 SSO 身份验证。 这篇文章向您展示了如何将 PingOne 设置为…

js中 = 等号赋值的问题,Js中对象的引用问题,深浅拷贝

js "" 赋值符号 在js中 “”对于基本数据类型是赋值符号&#xff0c;比较&#xff08; 或 &#xff09;的时候是值&#xff1b;对于引用数据类型-对象来说 是地址引用&#xff0c;比较的时候是比较的地址。 基本数据类型和引用数据类型的比较 let a 3; let b a;c…

Go是一门面向对象编程语言吗

本文首发自「慕课网」&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"&#xff01; 作者&#xff1a;tonybai|慕课网讲师 Go语言已经开源13年了&#xff0c;在近期TIOBE发布的2023年3月份的编程语言排行榜中&#xff0c;…

Go面向对象

前言 Go也有面向对象 面向对象引入: 用面向对象好啊 结构体定义 GO中的结构体和其他语言中的class是同一个等级的 这个就懒得写了 , 直接贴一个 内存分析 当实例化一个结构体的时候,分配一份内存空间. 结构体实例的创建 package main import "fmt" type Te…

计组第一章——计算机组成的基本认识

计算机——> 数值计算——> 处理电信号——> 基本单元&#xff08;逻辑元件&#xff09; 电子管——> 晶体管——>中小规模集成电路 ——>大规模&#xff0c;超大规模集成电路 机器字长&#xff1a;计算机一次整数运算所能处理的二进制位数 解析存储器中的程…

Vue——组件 v-model

目录 ​ v-model 的参数​ 多个 v-model 绑定​ 处理 v-model 修饰符​ v-model 可以在组件上使用以实现双向绑定。 首先让我们回忆一下 v-model 在原生元素上的用法&#xff1a; <input v-model"searchText" />在代码背后&#xff0c;模板编译器会对 v-…

工程日记的感悟

我个人很喜欢工程日记&#xff0c;好像一片自己一亩三分地一样&#xff0c;自己想弄些啥&#xff0c;就弄些啥。 人需要这份自由&#xff0c;需要这份能动性&#xff0c;因为人是创造者。 在《从小工到专家》的书中所要求的条目之中&#xff0c;有一条&#xff0c;就是工程日志…

最详细的Ubuntu服务器搭建Stable-Diffusion教程(无显卡,仅用CPU)

1. 首先安装基本工具 # 安装python环境 sudo apt install wget git若已经安装过请忽略 2. 安装miniconda&#xff08;也可以自己下载python&#xff09; 下载最新的安装包 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh执行安装 ./Minicon…

NumPy 秘籍中文第二版:十二、使用 NumPy 进行探索性和预测性数据分析

原文&#xff1a;NumPy Cookbook - Second Edition 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 在本章中&#xff0c;我们涵盖以下秘籍&#xff1a; 探索气压探索日常气压范围研究年度气压平均值分析最大可见度用自回归模型预测气压使用移动平均模型预测气压研究年…

HTML svg 之<path>使用

<path> 元素用于定义一个路径。 一、命令 下面的命令可用于路径数据&#xff1a; 命令字母示意描述(小写表示相对于上个坐标的位移,相对路径)M(m) x ymoveto移动到(x,y)L(l) x ylineto画一条直线到(x,y)H(h) xhorizontal lineto水平画一条直线到 Xv(v) yvertical linet…

CVE漏洞复现-CVE-2022-22965-Spring-RCE漏洞

CVE-2022-22965-Spring-RCE漏洞 漏洞概况与影响 Spring framework 是Spring 里面的一个基础开源框架&#xff0c;其目的是用于简化 Java 企业级应用的开发难度和开发周期,2022年3月31日&#xff0c;VMware Tanzu发布漏洞报告&#xff0c;Spring Framework存在远程代码执行漏洞…

JAVAWeb05-Tomcat

1. Tomcat 1.1 概述 1.1.1 官方文档 地址: https://tomcat.apache.org/tomcat-8.0-doc/ 1.1.2 WEB 开发介绍 WEB&#xff0c;在英语中 web 表示网/网络资源(页面,图片,css,js)意思&#xff0c;它用于表示 WEB 服务器(主机)供浏览器访问的资源WEB 服务器(主机)上供外界访问…

终于见识到 Python 的天花板。。

Python 有很多衍生方向&#xff0c;比如 web 开发、网络爬虫、数据分析、数据挖掘、机器学习、人工智能等等&#xff0c;就业范围是很广的&#xff0c;Python 相较于别的编程语言对小白入门还是很友好的&#xff0c; Python 入门推荐这份学习资料&#xff1a;PYTHON全案例实践…

【基础知识】PCB布局设计入门步骤

准备是成功的基石&#xff0c;在PCB设计中也是如此。改进和增长将伴随经验&#xff0c;首先做好准备能够充分利用经验获得成功。为了帮助你做好准备&#xff0c;下面分享一些基本的PCB布局设计步骤。 从良好的原材料入手是您PCB布局设计的第一步 无论打算执行什么任务&#xff…

Vue3——一文入门Vue3

Vue3的优势 1. 性能的提升 打包大小减少41% 初次渲染快55%&#xff0c;更新渲染快133% 内存减少54% … 2. 源码的升级 使用Proxy代替defineProperty实现响应式 重写虚拟DOM的实现和Tree-Shaking … 3. 拥抱TypeScript Vue3可以更好的支持TypeScript 4. 新的特性 1.C…

Java 进阶(2) Collection集合

集合的概念 概念&#xff1a;集合是java中提供的⼀种容器&#xff0c;可以⽤来存储多个数据。 数组&#xff1a;存储⼀组相同数据类型的数据结构。 局限&#xff1a;定长 集合&#xff1a;动态存放多个对象。 动态&#xff1a;集合的⼤⼩随着存储的数据量⽽改变。 多个&…

python界面开发案例:制作一个计算器软件

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 在我们手机上大家都有一个计算器&#xff0c;对吧 那它这功能是怎么实现的呢&#xff1f; 今天我们在电脑上来实现一个电脑端计算器界面~ 开发环境&#xff1a; Python 3.8 / 编译器 Pycharm 2021.2版本 / 编辑器 本文所有…

leedcode刷题(5)

各位朋友们&#xff0c;大家好&#xff0c;今天是我leedcode刷题的第五篇&#xff0c;我们一起来看看吧。 文章目录栈的压入&#xff0c;弹出序列题目要求用例输入提示做题思路代码实现C语言代码实现Java代码实现最小栈题目要求用例输入提示做题思路代码实现Java代码实现栈的压…

MATLAB绘制局部放大图

MATLAB绘制局部放大图 1 工具准备 MATLAB官网-ZoomPlot(Kepeng Qiu. Matlab Central, 2022) 初始数据图绘制完成后&#xff0c;调用以下代码&#xff1a; %% 添加局部放大 zp BaseZoom(); zp.plot;1.1 具体绘制步骤 具体绘制步骤如下&#xff1a; 通过鼠标左键框选作图区…