• Java Web教程——检视阅读


    Java Web教程——检视阅读

    参考

    java web入门——概念理解、名词解释

    Java Web 教程——w3school 蓝本

    JavaWeb学习总结(一)——JavaWeb开发入门

    小猴子monkey1024的Java教程

    基本学习点:

    HTML

    CSS

    JS

    JQuery

    XML

    Tomcat

    Servlet

    略读

    Java的Web框架虽然各不相同,但基本也都是遵循特定的路数的:使用Servlet或者Filter拦截请求,使用MVC的思想设计架构,使用约定,XML或 Annotation实现配置,运用Java面向对象的特点,面向对象实现请求和响应的流程,支持Jsp,Freemarker,Velocity等视图。

    基本上所有的java web应用都是基于Servlet规范,哪些常用框架如Struts,Spring MVC只是对Servlet规范的封装而已。

    web.xml节点加载顺序:

    可以肯定的是,节点的加载顺序与它们在 web.xml 文件中的先后顺序无关。即不会因为 filter 写在 listener 的前面而会先加载 filter。 加载顺序是:[context-param -> listener -> filter -> servlet] ,而同类型节点之间的实际程序调用的时候的顺序是根据对应的 mapping 的顺序进行调用的。

    Java Web简介

    Java Web,是用Java技术来解决相关web互联网领域的技术总和。

    理解HTTP

    HTTP是基于TCP协议的。TCP负责数据传输,而HTTP只是规范了TCP传输的数据的格式。

    HTTP服务的底层实现就是socket编程。

    示例:基于socket编写一个简单的HTTP server。

    这是一个实现HTTP 1.0的服务器,对于所有的HTTP请求,会把HTTP请求头响应回去。 这个程序说明了web服务器处理请求的基本流程,JSP、Servlet、Spring MVC等只是在 这个基础上嫁了许多方法,以让我们更方面的编写web应用。web服务器不仅可以基于多线程, 也可以基于多进程、Reactor模型等。

    HTTP 1.1: HTTP 1.1也是在这个思路的基础上实现的,即多个HTTP请求都在一个TCP连接中传输。对于HTTP 1.1,如何区分出每个HTTP请求很重要, 比较简单的可以是用过Content-Length判断一条请求是否结束。如果一个HTTP请求数据较多,往往采用Chunked方式 。

    public class MyHttpServer {
    
        private static transient final Logger logger = LoggerFactory.getLogger(MyHttpServer.class);
    
        public static void main(String[] args) throws IOException {
            int port =9000;
            ServerSocket socket = new ServerSocket(port);
            logger.error("启动服务,绑定端口: " + port);
            //使用带有ThreadFactory参数的ThreadPoolExecutor构造方法哦,这样你就可以方便的设置线程名字。
            //创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。创建线程池的时候请使用带ThreadFactory的构造函数,并且提供自定义ThreadFactory实现或者使用第三方实现。
            //ThreadFactoryBuilder需要guavay依赖
             //线程池的标准创建方法
            ThreadFactory socketThreadFactory = new ThreadFactoryBuilder().setNameFormat("socket-thread-%d").build();
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(30,60,3000,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(50),socketThreadFactory,new ThreadPoolExecutor.AbortPolicy());
            while (true){
                Socket clientSocket = socket.accept();
                logger.error("新的连接" + clientSocket.getInetAddress() + ":" + clientSocket.getPort());
                threadPoolExecutor.execute(new SocketHandler(clientSocket));
            }
        }
    }
    
    public class SocketHandler implements Runnable {
        private static transient final Logger logger = LoggerFactory.getLogger(SocketHandler.class);
        final static String CRLF = "
    ";
    
        private Socket clientSocket;
    
        public SocketHandler(Socket clientSocket) {
            this.clientSocket = clientSocket;
        }
    
        public void handleSocket(Socket clientSocket) throws IOException {
            BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())));
            try {
                String requestHeader = "";
                String s = "";
                //注意s = reader.readLine() 赋值
                while ((s = reader.readLine()) != null) {
                    s += CRLF;  // 2 很重要,默认情况下in.readLine的结果中`
    `被去掉了
                    requestHeader = requestHeader + s;
                    if (s.equals(CRLF)) {
                        break;
                    }
                }
    
                String responseBody = "客户端的请求头是:
    " + requestHeader;
                logger.error(responseBody);
                String responseHeader = "HTTP/1.0 200 OK
    " +
                        "Content-Type: text/plain; charset=UTF-8
    " +
                        "Content-Length: " + responseBody.getBytes().length + "
    " +
                        "
    ";
                logger.error("响应头:" + responseHeader);
                writer.write(responseHeader);
                writer.write(responseBody);
                writer.flush();
            } finally {
                writer.close();
                reader.close();
                clientSocket.close();
            }
        }
    
        @Override
        public void run() {
            try {
                logger.error("当前线程名:"+Thread.currentThread().getName());
                handleSocket(clientSocket);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    guava依赖用于线程池的 ThreadFactoryBuilder() 线程工厂的创建。

    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>18.0</version>
    </dependency>
    

    运行:

    #变更cmd运行窗口的编码格式为utf-8 ,否则会乱码
    chcp 65001
    #curl 是一种命令行工具,作用是发出网络请求,然后获取数据
    curl -i http://127.0.0.1:9000
    

    curl命令详解参考

    或者浏览器执行:

    http://127.0.0.1:9000/?happy=happy
    

    命令行运行输出:

    浏览器输出:

    ERROR - 新的连接/127.0.0.1:59037
    ERROR - 当前线程名:socket-thread-7
    ERROR - 客户端的请求头是:
    GET /?happy=happy HTTP/1.1
    Host: 127.0.0.1:9000
    Connection: keep-alive
    Cache-Control: max-age=0
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
    Accept-Encoding: gzip, deflate, br
    Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
    
    
    ERROR - 响应头:HTTP/1.0 200 OK
    Content-Type: text/plain; charset=UTF-8
    Content-Length: 457
    
    
    ERROR - 新的连接/127.0.0.1:59038
    ERROR - 当前线程名:socket-thread-8
    ERROR - 客户端的请求头是:
    GET /favicon.ico HTTP/1.1
    Host: 127.0.0.1:9000
    Connection: keep-alive
    Pragma: no-cache
    Cache-Control: no-cache
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
    Accept: image/webp,image/apng,image/*,*/*;q=0.8
    Referer: http://127.0.0.1:9000/?happy=happy
    Accept-Encoding: gzip, deflate, br
    Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
    
    
    ERROR - 响应头:HTTP/1.0 200 OK
    Content-Type: text/plain; charset=UTF-8
    Content-Length: 442
    

    注意:之所以后台会接收到2个请求,这是浏览器内置的请求方式,比如,除了我们想要的请求外,浏览器还请求了favicon.ico,即网站的图标,所以会有两个响应。

    报错:

    响应没有得到数据,只有一个响应头:

    这是因为在读取流的每一行数据时没有把读到的数据赋值给s。(s = reader.readLine())

        while ((s = reader.readLine()) != null) {
                    s += CRLF;  // 2 很重要,默认情况下in.readLine的结果中`
    `被去掉了
                    requestHeader = requestHeader + s;
                    if (s.equals(CRLF)) {
                        break;
                    }
                }
    

    从JSP开始

    JSP最合适的用途是用作MVC中的视图,而不是和HTML一起混合编码 (例如把从数据库拉取数据也放入JSP中写)

    待细学。

    理解Servlet

    待细学。

    Servlet如何返回JSON数据

    response.setContentType("text/html;charset=UTF-8");
    

    修改为

    response.setContentType("application/json;charset=UTF-8");
    

    过滤器与监听器

    过滤器与监听器

    过滤器

    过滤器(Filter),并非必须,但很实用。

    过滤器是一种设计模式,主要用来封装Servlet中一些通用的代码。在web.xml中配置哪些URL对应哪些过滤器。

    一个过滤器的写法如下:

    public void doFilter(ServletRequest request , ServletResponse response , FilterChain chain) {
        //处理 request
        chain.doFilter(request, response);
        //处理 response
    }
    

    假设针对一URL定义了3个过滤器,分别是MyFilter1、MyFilter2、MyFilter3,在web.xml中也是按照这个顺序设置的, 那么过滤器和Servlet的执行顺序如下:

    • MyFilter1中处理request的代码;
    • MyFilter2中处理request的代码;
    • MyFilter3中处理request的代码;
    • 相应的Servlet;
    • MyFilter3中处理response的代码;
    • MyFilter2中处理response的代码;
    • MyFilter1中处理response的代码;

    之所以能达到这样的效果,chain.doFilter(request, response);起到了很大的作用。 值得注意的是,如果每个Filter没有到达chain.doFilter就返回了,那么后续的Filter或者Servlet也就不会执行。

    监听器

    当某个事件发生时候,监听器里的方法会被调用。例如Tomcat容器启动时、销毁时,session创建时、销毁时。

    Tomcat的运行机制

    Tomcat 的运行机制

    在本手册“理解HTTP”中给出了一个简单的服务器代码,Tomcat的设计思路也是类似的。

    Tomcat是一个servlet容器,其运行机制可参考如下:

    先不去管技术细节,对一个servlet容器,它首先要做以下事情:

    1:实现Servlet api规范。这是最基础的一个实现,servlet api大部分都是接口规范。如request、response、session、cookie。为了我们应用端能正常使用,容器必须有一套完整实现。

    2:启动Socket监听端口,等待http请求。

    3:获取http请求,分发请求给不同的协议处理器,如http和https在处理上是不一样的。

    4:封装请求,构造HttpServletRequest。把socket获取的用户请求字节流转换成java对象httprequest。构造httpResponse。

    5:调用(若未创建,则先加载)servlet,调用init初始化,执行servlet.service()方法。

    6:为httpResponse添加header等头部信息。

    7:socket回写流,返回满足http协议格式的数据给浏览器。

    8:实现JSP语法分析器,JSP标记解释器。JSP servlet实现和渲染引擎。

    9:JNDI、JMX等服务实现。容器一般额外提供命名空间服务管理。

    10:线程池管理,创建线程池,并为每个请求分配线程。

    Tomcat有自己的类加载机制。可以参考:

    Java类加载原理解析

    深入探讨 Java 类加载器

    Tomcat类加载器体系结构

    Tomcat 8 权威指南

    Spring MVC

    Spring与依赖注入

    依赖注入是反转控制的一种。

    什么是反转控制?

    我们平常写程序,需要什么对象,就在代码里显式地new一个出来然后使用,这是我们自己去控制对象的生成。 而反转控制是让Spring(或者类似的其他工具)帮忙去生成我们需要的对象,也就是说对象的生成的控制权交给Spring了。

    当然,Spring需要依据一定的规则去生成对象,这个规则就在我们写的xml配置文件、或者代码中添加的注解之中。 换句话说,我们不要生成对象,但是要去写配置。

    反转控制的实现中应用了大量的反射。

    依赖注入

    声明依赖关系,Spring将对象A需要的对象B注入到对象A中。

    Spring与面向切面编程

    面向切面编程是一种编程模式。

    使用动态代理可以实现面向切面编程。

    这个教程一般,不继续了。

    疑问

    Q:过滤器与监听器?

    Q:Servlet?

    其他

     #basedir=你的mysql目录,datadir=数据存放目录
    basedir="C:/Program Files/MySQL/MySQL Server 5.7/"
    datadir=C:/ProgramData/MySQL/MySQL Server 5.7Data
    

    springMVC中文乱码问题

  • 相关阅读:
    每天备份数据库中的表
    IE9相容問題-childNodes行為改變
    查找含有某字符的存儲過程
    弹出SQL报表的时候,出现空白的解决方法
    转:Page.ClientScript.RegisterStartupScript(me.GetType(),"script1","<script>alert('111');</script>")
    java核心技术记录之java术语
    Head First 设计模式笔记:单例模式
    多对一关系实体中,多的一方所关联的一实体的实例化问题
    ajax请求返回json数据弹出下载框的解决方法
    java核心技术记录
  • 原文地址:https://www.cnblogs.com/castamere/p/12794206.html
Copyright © 2020-2023  润新知