JavaWeb基础(框架入门)

JavaWeb

1.基本概念

1.前言

  • web,网页
  • 静态web
    • html,css
    • 提供给所有人看始终不会改变
  • 动态web
    • 提供给所有人看的数据始终会变化
    • 技术栈:JSP/Servlet,ASP,PHP

动态web资源技术开发技术统称为javaweb

2.web应用程序

应用程序编写完成之后,想给外界访问,需要一个服务器统一管理

3.动态web

image-20201111160954917

2.web服务器

1.JSP/Servlet

  • sun公司主推B/S架构
  • 基于java
  • 可以承载三高问题带来的影响
  • 语法像ASP

2.web服务器

服务器是被动操作,用来处理用户的请求和返回响应信息

  • IIS

    • 微软,ASP,window自带
  • Tomcat

    1. 下载Tomcat压缩包
    2. 解压Tomcat压缩包到/Library/下
    3. 终端输入cd /Library/Tomcat/bin
    4. sudo chmod 755 *.sh
    5. 启动——sudo sh ./startup.sh
    6. 关闭——sh ./shutdown.sh

    image-20201111163320267

    修改Tomcat的端口号

    <Connector port="8888" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443" />
    

3.HTTP

HTTP(超文本传输协议),通常运行在TCP上

1.两个时代

  • http1.0
    • HTTP/1.0:短连接,获取一个资源后断开
  • http1.1
    • HTTP1.1:长连接,获取多个资源

==HTTP格式==

4.Servlet

1.开发流程

本质:一个接口,一个统一的web应用规范,一个协议

  • 编写一个类,实现Servlet接口
  • 把开发好的java类部署到web服务器中

把实现了Servlet接口的java程序叫做Servlet

2.HelloServlet

开发流程

  1. 构建普通Maven工程,删掉src目录,以后学习就在这个项目中建立Moudel,这个空的工程就是Maven主工程

  2. 关于Maven父子工程的理解:

    • 父项目中会多出
    <modules>
      	<module>study</module>
    </modules>
    
    • 子项目中会有
    <parent>
        <artifactId>com.hznu.ch</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    

    父项目中的依赖子项目都可以使用,相当于继承父类

  3. Maven结构图

    • image-20201112103917096
    • image-20201112092850556

  4. 编写Servlet程序

    1. 编写普通类,实现Servlet接口,这里继承HttpServlet,并重写方法

    image-20201111205939071

    public class ServletTest extends HttpServlet {
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //设置字符编码
            request.setCharacterEncoding("utf8");
            //从 request 对象中获取username,password
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            request.setAttribute("username", username);
            request.setAttribute("password", password);
            request.getRequestDispatcher("/new.jsp").forward(request, response);
        }
    }
    
    1. 编写jsp页面
    <html>
    <body>
    <h2>This is new Page</h2>
    username: <%=request.getParameter("username") %>
    <br>
    password: <%=request.getParameter("password") %>
    </body>
    </html>
    
  5. 编写Servlet映射(web.xml)

<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <servlet>
        <!--映射名-->
        <servlet-name>ServletTest</servlet-name>
        <!--对应的类-->
        <servlet-class>com.hznu.ch.servlet.ServletTest</servlet-class>
    </servlet>

    <servlet-mapping>
        <!--映射名-->
        <servlet-name>ServletTest</servlet-name>
        <!--url-->
        <url-pattern>/ServletTest</url-pattern>
    </servlet-mapping>
</web-app>

img

  1. 配置Tomcat

image-20201112104426230

image-20201112104528017

  1. 访问资源文件

image-20201112104631946

参考文献

idea搭建可运行Servlet的Web项目[maven]

3.Mapping

  • 一个Servlet对应一个页面
<servlet>
    <servlet-name>ServletTest</servlet-name>
    <servlet-class>com.hznu.ch.servlet.ServletTest</servlet-class>
</servlet>
  • 一个Servlet对应多个页面
<servlet-mapping>
    <servlet-name>ServletTest</servlet-name>
    <url-pattern>/ServletTest</url-pattern>
</servlet-mapping>
  • 添加后缀

*.ch将ch后缀名的url映射到某个Servlet

4.优先级问题

  1. 精确匹配,servlet-mapping1:/user/users.html,servlet-mapping2:/*。当一个请求http: //localhost:8080/appDemo/user/users.html来的时候,servlet-mapping1匹配到,不再用servlet-mapping2匹配
  2. 路径匹配,先最长路径匹配,再最短路径匹配servlet-mapping1:/user/,servlet-mapping2:/。当一个请求http: //localhost:8080/appDemo/user/users.html来的时候,servlet-mapping1匹配到,不再用servlet-mapping2匹配
  3. 扩展名匹配,servlet-mapping1:/user/,servlet-mapping2:.action。当一个请求http: //localhost:8080/appDemo/user/addUser.action来的时候,servlet-mapping1匹配到,不再用servlet-mapping2匹配
  4. 缺省匹配,以上都找不到servlet,就用默认的servlet,配置为/

5.原理

明确几件事:Tomcat的作用是将Socket传来的数据变成ServletRequest类,交给Servlet处理

具体可以查看知乎大佬,里面有一个例子可以明白Tomcat做的最基本的事情,我来总结一下哈

Tomcat对Socket数据进行封装,请求包装成ServletRequest类,响应包装成ServletResponse类,然后都传给我们实现了Servlet接口的类,对这两个数据进行处理,再由Tomcat返回给客户端

Tomcat和Servlet的协同关系以及Servlet的生命周期

img

6.ServletContext

image-20201113182716449

1.Servlet通信

//存入数据到ServletContext
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        context.setAttribute("username", "陈恒");
    }
}

//读取ServletContext数据
public class GetNameServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        resp.setCharacterEncoding("utf-8");
        ServletContext context = this.getServletContext();
        resp.getWriter().print("姓名:" + context.getAttribute("username").toString());
    }
}

2.获取初始化参数

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        resp.getWriter().print("参数:" + context.getInitParameter("url"));
    }
}
<context-param>
    <param-name>url</param-name>
    <param-value>jdbc:mysql://localhost:3306?username=123&amp;password=hhh</param-value>
</context-param>

3.请求转发

image-20201114183012963

请求转发的url不会变,区别于重定向

简单解释:
浏览器A请求服务器B,B无法完成A所有的请求任务,所以直接将请求发送给服务器C了,这里不再经过A了,B发送给C的同时带着A给B的数据,然后再由C回传给A它之前请求的资源

实际整个转发过程:
客户浏览器发送http请求—>web服务器接受此请求—>调用内部的一个方法在容器内部完成请求处理和转发动作—>将目标资源发送给客户。在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的

public class RequestForward extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        context.getRequestDispatcher("/first.jsp").forward(req, resp);
    }
}

4.读取资源文件

1.防止maven导出资源失败

就比如说在java文件夹下的*.properties文件(ch.properties)无法被maven加载到target包中

image-20201113195405076

在pom.xml文件中的<build></build>中添加这一段来要求maven添加java文件夹中的xml和properties文件

<resources>
    <resource>
        <directory>src/main/java</directory>
        <includes>
            <include>**/*.properties</include>
            <include>**/*.xml</include>
        </includes>
        <filtering>true</filtering>
    </resource>
</resources>

image-20201113195633357

同时我们也可以发现被maven打包的项目会自动生成一个classes目录(类路径),db.properties和com都在它的目录下面

2.maven生成的项目结构

image-20201113202457284

3.读取配置文件

进入正题,怎么读取配置文件的源码

public class GetResourceServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        InputStream is = context.getResourceAsStream("/WEB-INF/classes/db.properties");
        Properties prop = new Properties();
        prop.load(is);
        resp.getWriter().print(prop.getProperty("username"));
    }
}

/*资源文件db.properties
username=ch
password=123
*/

7.HttpServletResponse

观察这个类的时候发现HttpServletResponse是装饰者模式,因为有ServletResponseWrapper类和HttpServletResponseWrapper类负责对ServletResponse和HttpServletResponse进行装饰

public class ServletResponseWrapper implements ServletResponse {
    private ServletResponse response;//内置了一个被装饰者对象
  	......
}

ServletResponse源码

//这个类是响应报文的接口
public interface ServletResponse {
    String getCharacterEncoding();

    String getContentType();

    ServletOutputStream getOutputStream() throws IOException;//输出字节流

    PrintWriter getWriter() throws IOException;//输出字符流

    void setCharacterEncoding(String var1);//设置编码格式

    void setContentLength(int var1);

    void setContentLengthLong(long var1);

    void setContentType(String var1);//设置文件格式 text/html...

    void setBufferSize(int var1);

    int getBufferSize();

    void flushBuffer() throws IOException;

    void resetBuffer();

    boolean isCommitted();

    void reset();

    void setLocale(Locale var1);

    Locale getLocale();
}

HttpServletResponse部分源码

//HttpServletResponse在ServletResponse上封装了关于HTTP的一些内容
public interface HttpServletResponse extends ServletResponse {
    int SC_CONTINUE = 100;
    int SC_SWITCHING_PROTOCOLS = 101;
    int SC_OK = 200;
    int SC_CREATED = 201;
    int SC_ACCEPTED = 202;
    int SC_NON_AUTHORITATIVE_INFORMATION = 203;
    int SC_NO_CONTENT = 204;
    int SC_RESET_CONTENT = 205;
    int SC_PARTIAL_CONTENT = 206;
    int SC_MULTIPLE_CHOICES = 300;
    int SC_MOVED_PERMANENTLY = 301;
    int SC_MOVED_TEMPORARILY = 302;
    int SC_FOUND = 302;
    int SC_SEE_OTHER = 303;
    int SC_NOT_MODIFIED = 304;
    int SC_USE_PROXY = 305;
    int SC_TEMPORARY_REDIRECT = 307;
    int SC_BAD_REQUEST = 400;
    int SC_UNAUTHORIZED = 401;
    int SC_PAYMENT_REQUIRED = 402;
    int SC_FORBIDDEN = 403;
    int SC_NOT_FOUND = 404;
    int SC_METHOD_NOT_ALLOWED = 405;
    int SC_NOT_ACCEPTABLE = 406;
    int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
    int SC_REQUEST_TIMEOUT = 408;
    int SC_CONFLICT = 409;
    int SC_GONE = 410;
    int SC_LENGTH_REQUIRED = 411;
    int SC_PRECONDITION_FAILED = 412;
    int SC_REQUEST_ENTITY_TOO_LARGE = 413;
    int SC_REQUEST_URI_TOO_LONG = 414;
    int SC_UNSUPPORTED_MEDIA_TYPE = 415;
    int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
    int SC_EXPECTATION_FAILED = 417;
    int SC_INTERNAL_SERVER_ERROR = 500;
    int SC_NOT_IMPLEMENTED = 501;
    int SC_BAD_GATEWAY = 502;
    int SC_SERVICE_UNAVAILABLE = 503;
    int SC_GATEWAY_TIMEOUT = 504;
    int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
  	......
}

主要看一波状态码,以后不知道可以到这个类查了

  • 200——成功状态码
  • 3xx——请求重定向
    • 302——重定向
    • 307——请求转发
  • 4xx——找不到资源
    • 404——请求的资源不存在
  • 5xx——服务器代码错误
    • 502——网关错误

基本应用

1.下载文件
public class DownloadServlet extends HttpServlet {

    /**
     * 1.文件路径
     * 2.获取文件名
     * 3.设置HTTP头部可以提供下载,并就中文文件名转码
     * 4.获取文件输入流
     * 5.输入到HTTP响应报文的输出流中
     * */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String realPath = "xxx/xxx/xxx/xxx.png";
        String fileName = realPath.substring(realPath.lastIndexOf('/'));
        resp.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        FileInputStream fis = new FileInputStream(realPath);
        int len = 0;
        byte[] bytes = new byte[1024];
        while ((len = fis.read(bytes)) > 0) {
            resp.getOutputStream().write(bytes);
        }
    }
}
2.验证码的实现
public class ImageServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //浏览器自动刷新
        resp.setHeader("refresh", "3");

        //内存中创建一个图片
        BufferedImage bufferedImage = new BufferedImage(140, 20, BufferedImage.TYPE_INT_RGB);

        //得到图片
        Graphics2D graphics = (Graphics2D) bufferedImage.getGraphics();

        //设置图片背景颜色
        graphics.setColor(Color.WHITE);
        graphics.fillRect(0, 0, 100, 20);

        //给图片写数据
        graphics.setColor(Color.BLUE);
        graphics.setFont(new Font(null, Font.BOLD, 20));
        String str = productRandomNumber();
        System.out.println("str=" + str);
        graphics.drawString(str, 0, 20);

        //请求用图片的方式打开
        resp.setContentType("image/jpeg");

        //网站存在缓存,不让浏览器缓存
        resp.setDateHeader("expires", -1);
        resp.setHeader("Cache-Control", "no-cache");
        resp.setHeader("Pragma", "no-cache");

        //把图片写给浏览器
        ImageIO.write(bufferedImage, "jpg", resp.getOutputStream());
    }

    private String productRandomNumber() {
        Random random = new Random();
        String ans = random.nextInt(9999999) + "";
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 7 - ans.length(); i++)
            sb.append('0');
        return sb.toString() + ans;
    }
}
3.实现重定向

重定向url会改变

image-20201114153026143

简单解释过程:
如图,浏览器A发送请求服务器B,B不能完全完成A想要的任务,所以B返回告诉A,让A去找服务器C完成接下来的任务,此时浏览器A重新发送新的请求给C,直到完成任务,这是一种直白的重定向解释。

实际整个重定向过程:
客户浏览器发送http请求—>web服务器接受后发送302状态码响应及对应新的location给客户浏览器—>客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址—>服务器根据此请求寻找资源并发送给客户。在这里location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的路径,客户可以观察到地址的变化的

resp.sendRedirect("/s2/image");
//在这里等价于下面两句

//resp.setHeader("Location", "/s2/image");
//resp.setStatus(302);

image-20201114155120184

这张图验证了重定向的操作流程,响应的状态码302——重定向,重定向的Location是/s2/image也没错

8.HttpServletRequest

基本应用

1.获取请求的参数
String getParameter(String var1);//获取单个参数
Enumeration<String> getParameterNames();//获取所有的name属性的值
String[] getParameterValues(String var1);//获取参数数组
2.请求转发
RequestDispatcher getRequestDispatcher(String var1);
3.注意点
resp.sendRedirect("/s2/success.jsp");//重定向因为需要浏览器再发送一次请求,所以需要包括上下文的url
req.getRequestDispatcher("/success.jsp").forward(req, resp);//请求转发是在Tomcat里面完成的,处在同一个上下文,所以不需要包括上下文

5.Cookie&Session

1.保存会话的两种技术

cookie

  • 服务端给客户端一个信件,客户端下次访问服务端带上信件就可以了
  • 客户端技术(响应,请求)

session

  • 服务器登记你来过,下次来的时候匹配你
  • 服务器技术(把信息存放到session中)

2.Cookie

  1. 从请求中拿到cookie信息
  2. 服务器响应给客户端cookie
Cookie[] cookies = req.getCookies();//获得cookie数组
cookie.getName()//获得cookie的key
cookie.getValue()//获得cookie的value
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");//新建一个cookie
cookie.setMaxAge(24 * 60 * 60);//设置cookie1的有效期
resp.addCookie(cookie);//响应给客户端一个cookie

一个浏览器可以有多个cookie

3.Session

HttpSession session = req.getSession();//获取session
session.setAttribute("name", "陈恒");//设置键值对
String id = session.getId();//获取sessionid
session.isNew()//判断session是不是新创建的
String name = (String) session.getAttribute("name");//根据key获取value
session.removeAttribute("name");//移除session中某个键值对
session.invalidate();//清除session

配置web.xml自动失效的时限

<!--设置session默认的失效时间,这里以分钟作为单位-->
<session-config>
    <session-timeout>1</session-timeout>
</session-config>

cookie和session的区别

  • Cookie是把用户的数据写给用户的浏览器,浏览器保存(可以保存多个)
  • Session是把用户的数据写到用户独占Session中,服务端保存(保存重要的信息,减少服务器资源的浪费)
  • Session对象由服务器创建,某一时刻一个浏览器只能有一个Session

Cookie是把用户的数据写给浏览器,每次用户访问的时候会携带Cookie中用户信息,从而完成响应的操作

Seesion是把用户的数据存放在服务器中,把SessionId以Cookie的形式保存在浏览器中,用户每次访问的时候携带SessionId,服务器根据SessionId找到对应用户信息,从而完成响应操作

image-20201116211106685

从上面这张图我们也可以看出来,我们并没有存储JSESESSION这个Cookie值,所以我们有理由相信服务器帮我们把SessionId写进客户端的Cookie里,以便我们下次访问服务器的时候可以根据这个SessionId找到对应的用户信息

使用场景:

  • 保存一个登录用户的信息
  • 购物车信息
  • 在整个网站中经常使用的数据

6.JSP

1.什么是JSP

Java Server Pages:java服务器端页面,也和Servlet一样,用于动态Web技术

JSP像在写HTML

区别:HTML只给用户提供静态数据,JSP嵌入java代码,为用户提供动态数据

2.JSP原理

image-20201117201336438

进入IDEA的Tomcat工作目录,我们发现jsp变成了java代码

image-20201117201601061

浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet

JSP本质就是Servlet,因为HttpBase继承HttpServlet(我这里源码查看不了,但我看到网课上有的!!!)

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {
                   ......
                   
									//初始化jsp
                   public void _jspInit() {

                   }

                   //销毁jsp
                   public void _jspDestroy() {

                   }

                   //jsp服务
                   public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
                     throws java.io.IOException, javax.servlet.ServletException {

                     if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
                       final java.lang.String _jspx_method = request.getMethod();
                       if ("OPTIONS".equals(_jspx_method)) {
                         response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
                         return;
                       }
                       if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
                         response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
                         response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
                         return;
                       }
                     }

                     final javax.servlet.jsp.PageContext pageContext;
                     javax.servlet.http.HttpSession session = null;
                     final javax.servlet.ServletContext application;
                     final javax.servlet.ServletConfig config;
                     javax.servlet.jsp.JspWriter out = null;
                     final java.lang.Object page = this;
                     javax.servlet.jsp.JspWriter _jspx_out = null;
                     javax.servlet.jsp.PageContext _jspx_page_context = null;


                     try {
                       response.setContentType("text/html");
                       pageContext = _jspxFactory.getPageContext(this, request, response,
                                                                 null, true, 8192, true);
                       _jspx_page_context = pageContext;
                       application = pageContext.getServletContext();
                       config = pageContext.getServletConfig();
                       session = pageContext.getSession();
                       out = pageContext.getOut();
                       _jspx_out = out;

                       out.write("<html>\n");
                       out.write("<body>\n");
                       out.write("<h2>Hello World!</h2>\n");
                       out.write("</body>\n");
                       out.write("</html>\n");
                     } catch (java.lang.Throwable t) {
                       if (!(t instanceof javax.servlet.jsp.SkipPageException)){
                         out = _jspx_out;
                         if (out != null && out.getBufferSize() != 0)
                           try {
                             if (response.isCommitted()) {
                               out.flush();
                             } else {
                               out.clearBuffer();
                             }
                           } catch (java.io.IOException e) {}
                         if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
                         else throw new ServletException(t);
                       }
                     } finally {
                       _jspxFactory.releasePageContext(_jspx_page_context);
                     }
                   }

源码分析:

  1. 先做判断,查看请求方式
  2. 内置对象
final javax.servlet.jsp.PageContext pageContext;//页面上下文
javax.servlet.http.HttpSession session = null;//session
final javax.servlet.ServletContext application;//applicationcontext
final javax.servlet.ServletConfig config;//config
javax.servlet.jsp.JspWriter out = null;//输出
final java.lang.Object page = this;//当前页
HttpServletRequest req;//请求
HttpServletResponse resp;//响应
  1. 输出页面前增加的代码
response.setContentType("text/html");//设置响应的页面类型
pageContext = _jspxFactory.getPageContext(this, request, response,
                                          null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
  1. 输出页面
out.write("<html>\n");
out.write("<body>\n");
out.write("<h2>Hello World!</h2>\n");
out.write("</body>\n");
out.write("</html>\n");

3.JSP转化流程

image-20201117205659731

4.JSP基本语法

JSP表达式

<%--JSP表达式
作用:用来将程序输出,输出到客户端
<%= 变量或表达式%>
--%>

<%=new Date()%>

JSP脚本语言

<%--JSP脚本语言--%>
<%
    int sum = 0;
    for (int i = 0; i < 100; i++) {
        sum += i;
    }
    out.println(sum);
%>

JSP声明

jsp声明会被编译到JSP生成的Java类中,其他的则会被生成到_jspService方法中

<%!
    static {
        System.out.println("陈恒");
    }

    private int globalVar = 0;

    public void ch() {
        System.out.println("进入ch方法");
    }
%>
<%%>
<%=%>
<%!%>
<%----%>

5. 9大内置对象

  • PageContext:页面上下文:存储数据
  • Request:请求:存储数据
  • Response:响应
  • Session:session:存储数据
  • Application【ServletContext】:存储数据
  • config【ServletConfig】
  • out
  • page,几乎不用,可以不用了解
  • exception
pageContext.setAttribute("name1", "1");//保存的数据只在一个页面中有效
request.setAttribute("name2", "2");//一次请求有效
session.setAttribute("name3", "3");//一次会话有效,从SessionID生成到Cookie中的Session失效
application.setAttribute("name4", "4");//在服务器中有效,从打开服务器到关闭服务器,主要用于用户共同访问的数据,如仓库中的数据,或者用于统计人数(就好像有个全局变量去存储人数一样,而不是每一次查询都一个人一个人的数过来)等等

底层到高层(作用域):page->request->session->application

page1

<%
    pageContext.setAttribute("name1", "1");//保存的数据只在一个页面中有效
    request.setAttribute("name2", "2");//一次请求有效
    session.setAttribute("name3", "3");//一次会话有效,从打开浏览器到关闭
    application.setAttribute("name4", "4");//在服务器中有效,从打开服务器到关闭服务器
%>

<%

    //底层到高层(作用域):page->request->session->application
    String name1 = (String) pageContext.findAttribute("name1");
    String name2 = (String) pageContext.findAttribute("name2");
    String name3 = (String) pageContext.findAttribute("name3");
    String name4 = (String) pageContext.findAttribute("name4");
    String name5 = (String) pageContext.findAttribute("name5");
%>

<h1>${name1}</h1>
<h1>${name2}</h1>
<h1>${name3}</h1>
<h1>${name4}</h1>
<h1>${name5}</h1>

image-20201117232719846

page2

<%

    String name1 = (String) pageContext.findAttribute("name1");
    String name2 = (String) pageContext.findAttribute("name2");
    String name3 = (String) pageContext.findAttribute("name3");
    String name4 = (String) pageContext.findAttribute("name4");
    String name5 = (String) pageContext.findAttribute("name5");
%>

<h1>${name1}</h1>
<h1>${name2}</h1>
<h1>${name3}</h1>
<h1>${name4}</h1>
<h1>${name5}</h1>

image-20201117232734473

当跨页面时,pageContext和request就失效了

7.JavaBean

特定写法:

  • 无参构造函数
  • 属性private
  • 必须有get/set方法
  • 实现serializable接口

一般用来做和数据库的字段映射——ORM:对象关系映射

  • 表——类
  • 字段——属性
  • 行记录——对象

8.MVC三层架构

image-20201119222158987

9.Filter

这里只是简写,详见SpringBoot篇

下面是最基本的过滤器用法,将请求和响应的编码格式改为UTF-8以解决中文乱码问题

还有就是filter的配置(和servlet没多少差别)

public class FilterTest implements Filter {
    //随项目启动初始化
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    //过滤请求
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setCharacterEncoding("utf-8");
        servletResponse.setContentType("text/html;charset=UTF-8");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    //随项目关闭销毁
    public void destroy() {

    }
}
<filter>
    <filter-name>FilterTest</filter-name>
    <filter-class>com.hznu.ch.servlet.FilterTest</filter-class>
</filter>
<filter-mapping>
    <filter-name>FilterTest</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

10.Listener

实现一个监听器的接口

public class ListenerTest implements HttpSessionListener {
    private static final String ONLINE = "online";

    //创建session的监听
    public void sessionCreated(HttpSessionEvent se) {
        ServletContext ctx = se.getSession().getServletContext();
        Integer online = (Integer) ctx.getAttribute(ONLINE);
        if (online == null)
            ctx.setAttribute(ONLINE, 1);
        else
            ctx.setAttribute(ONLINE, (Integer) ctx.getAttribute(ONLINE) + 1);
    }


    //销毁session的监听
    public void sessionDestroyed(HttpSessionEvent se) {
        ServletContext ctx = se.getSession().getServletContext();
        Integer online = (Integer) ctx.getAttribute(ONLINE);
        if (online == null)
            ctx.setAttribute(ONLINE, 0);
        else
            ctx.setAttribute(ONLINE, (Integer) ctx.getAttribute(ONLINE) - 1);
    }
}

级别update classes and resources最低,restart最高

  • update resources ---- 更新静态的资源,比如html,js,css等 运行模式和调试模式都是立即生效;
  • update classes and resources ---- 更新java,jsp和静态资源(编写了jsp等静态资源
  • redeploy ----- 重新部署,发布到tomcat里,不重启tomcat,而是把原来的删掉,然后重新发布(编写了Java代码
  • restart server ----- 重启tomcat(编写了配置文件,重启服务

image-20201122153907891

11.JDBC

Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC也是Sun Microsystems的商标。我们通常说的JDBC是面向关系型数据库的

image-20201122155439516

1.JDBC固定套路

public class JDBCTest {

    public static void main(String[] args) throws Exception {
        String url = "jdbc:mysql://localhost:3306/m_test?useUnicode=true&characterEncoding=utf-8";
        String username = "root";
        String password = "XXXX";

        //1.加载mysql的驱动
        Class.forName("com.mysql.jdbc.Driver");

        //2.连接数据库
        Connection connection = DriverManager.getConnection(url, username, password);

        //3.数据库对象Statement,用于CURD
        Statement statement = connection.createStatement();

        //4.编写sql语句
        String sql = "select * from user";

        //5.查询出结果集
        ResultSet rs = statement.executeQuery(sql);

        //6.编写业务逻辑
        while (rs.next()) {
            System.out.println("id=" + rs.getObject("id"));
            System.out.println("username=" + rs.getObject("username"));
            System.out.println("password=" + rs.getObject("password"));
        }

        //7.关闭连接
        rs.close();
        statement.close();
        connection.close();
    }
}

2.事务

ACID,指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。一个支持事务(Transaction)的数据库,必须要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求

原子性:整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节

一致性:一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。

也就是说:如果事务是并发多个,系统也必须如同串行事务一样操作。其主要特征是保护性和不变性(Preserving an Invariant),以转账案例为例,假设有五个账户,每个账户余额是100元,那么五个账户总额是500元,如果在这个5个账户之间同时发生多个转账,无论并发多少个,比如在A与B账户之间转账5元,在C与D账户之间转账10元,在B与E之间转账15元,五个账户总额也应该还是500元,这就是保护性和不变性

隔离性:隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作,如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据

持久性:在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚

connection.setAutoCommit(false);//开启事务,false是开启
connection.commit();//事务提交
connection.rollback();//事务回滚
# 入门  JavaWeb 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×