[toc]

JavaWeb

1.编写Servlet

  • 重要补充:request是从服务器获取数据,response是从服务器向浏览器返回数据

  • 通过配置的maven新建webapp模板工程并且配置pom.xml文件(是mvn的核心文件)来导入Servlet的依赖

    • <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
      </dependency>
      
      1
      2
      3
      4
      5
      6
      7

      - 创建一个类继承HttpServlet,并重写Service方法

      - ```java
      public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
      res.getWriter().write("Hello servlet");//通过浏览器窗口输出Hello servlet
      }
  • 在web.xml里编写映射

    • 这里注意检查web.xml的版本,最好不要太旧

      • 可以直接复制这个xml粘贴(虽然不是很新,但是也不是太旧hh)

      • <?xml version="1.0" encoding="UTF-8"?>
        <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                              http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
                 version="3.1"
                 metadata-complete="true">
        </web-app>
        
        1
        2
        3
        4
        5
        6
        7
        8

        - 分别是两个标签的实现:servlet和servlet-mapping(是写在webapp这个大标签里的)

        - ```xml
        <servlet></servlet> 在向servlet或JSP页面制定初始化参数或定制URL时,必须首先命名servlet或JSP页面。Servlet元素就是用来完成此项任务的。
        <servlet-mapping></servlet-mapping> 服务器一般为servlet提供一个缺省的URL:
        <!--http://host/webAppPrefix/servlet/ServletName.这里就缺省了后面的url-->
        但是,常常会更改这个URL,以便servlet可以访问初始化参数或更容易地处理相对URL。在更改缺省URL时,使用servlet-mapping元素。
    • <servlet>
              <servlet-name>HelloServlet</servlet-name><!--注册servlet-->
          <servlet-class>HelloServlet</servlet-class><!--这个是文件的相对位置-->
      </servlet>
      <servlet-mapping>
          <servlet-name>HelloServlet</servlet-name><!--与上面的servletname需要一致-->
          <url-pattern>/cf</url-pattern><!--填写重定向后的地址-->
      </servlet-mapping>
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20

      - 启动tomcat服务器

      - 在idea的右上角选择本地的tomcat服务器,找到Deployment的选项窗口添加war包的位置
      - Application context是浏览器通过localhost:8080端口启动后的位置
      - ![image-20220706143752038](C:\Users\Leilei\Desktop\image-20220706143752038.png)

      - 通过localhost:8080加上Deployment窗口加上servlet的重定向来访问

      - ![image-20220706151026099](C:\Users\Leilei\Desktop\image-20220706151026099.png)

      - 补充:关于mapping

      - 一个servlet映射一个路径->只有访问指定的路径才可以得到信息

      - ```xml
      <servlet-mapping>
      <servlet-name>HelloServlet</servlet-name>
      <url-pattern>/cf</url-pattern>
      </servlet-mapping>
    • 一个servlet映射多个路径->只有其他的路径也可以得到信息

      • <!--这里通过cf1,cf2,cf都可以访问到原来的hello servlet-->
        <servlet-mapping>
            <servlet-name>HelloServlet</servlet-name>
            <url-pattern>/cf</url-pattern>
        </servlet-mapping>
            
        <servlet-mapping>
            <servlet-name>HelloServlet</servlet-name>
            <url-pattern>/cf1</url-pattern>
        </servlet-mapping>
            
        <servlet-mapping>
            <servlet-name>HelloServlet</servlet-name>
            <url-pattern>/cf2</url-pattern>
        </servlet-mapping>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9

        - 一个servlet可以指定通用映射路径(利用通配符*来解决)

        - ```xml
        <!--这时候也是不会进index.jsp,优先级相对高-->
        <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/cf/*</url-pattern>
        </servlet-mapping>
    • 自定义后缀实现请求映射

      • <!--这时候利用do后缀就可以进入
            但是前面不能加上任何路径
        -->
        <servlet-mapping>
            <servlet-name>HelloServlet</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14

        ### 2.ServletContext

        1. 解释:每一个web应用都有且仅有一个ServletContext对象,又称Application对象,从名称中可知,该对象是与应用程序相关的。在WEB容器启动的时候,会为每一个WEB应用程序创个对应的ServletContext对象。

        2. 作用

        - **共享数据**,可以通过一方来保存,另一方可以读取

        3. 两个小方法:

        - ```java
        getServletContext//设置储存的信息,以键值对的形式
        getAttribute//获取储存的信息,需要键的名为对象
  1. 具体实现:

    • public class Hello02 extends HttpServlet {//添加类
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              resp.setContentType("text/html;charset = utf-8");
              ServletContext context = this.getServletContext();//获取context对象
              String name = "借口";
              context.setAttribute("username", name);//设置添加的字符串,以键值对的形式
              System.out.println("添加成功");
          }
      }
      
      public class getC extends HttpServlet {//获取类
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              req.setCharacterEncoding("utf-8");
              ServletContext context = this.getServletContext();//同样是获取context对象,因为是全局的的,所以能找到里面所有的信息
              String username = (String) context.getAttribute("username");//以键名的形式获取
              resp.getWriter().write(username);
      
          }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14

      5. 配置web.xml

      6. 启动tomcat服务器分别访问两个类

      ### 3.请求转发

      - 不改变原来的地址,但是能够改变跳转的位置

      - 相当于是有三个人A,B,C ;A想要给C传达消息,但是A只能联系到B,而B作为传话筒将A的信息传给C,同样的C的信息也通过B传给了A,请求转发的作用就是B角色

      - ```java
      ServletContext context = this.getServletContext();//先获取context对象
      context.getRequestDispatcher("/cf").forward(req,resp);//调用getRequestDispatcher方法输入请求转发的地址,以及请求出去需要发送的req,resp->这样就可以将地址传给web.xml里的cf地址来跳转,然后将req,resp同时转给cf的地址

4.通过Servletcontext读取配置文件

  • 先创建一个ServletContext对象;调用getResourceAsStream方法将文件转化成流

  • 创建properties对象加载流,并获取信息

  • protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        Properties prop = new Properties();
        InputStream ras = context.getResourceAsStream("/WEB-INF/classes/db.properties");
        prop.load(ras);
        String username = prop.getProperty("username");
        String pwd = prop.getProperty("password");
        resp.getWriter().write(username+":"+pwd);
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29

    - 注意事项:(一定要写相对路径)现在写的类同时会产生class类,同样的properties配置文件也是在class下,而本类写的东西是要在同类的地方产生class->即现在要找的配置文件就是本类的WEB-INF的classes下面

    ### 5.Response

    从浏览器来的就叫request的呗,从我这边走出去的就叫response呗

    #### 1.下载

    1. 找到文件的地址,通过io流读写,并通过response的`getOutputStream`方法来写入

    2. 设置response的Header声明出是下载文件

    - ```java
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String realPath = "D:\\project\\java\\execrise\\project02\\src\\main\\resources\\a.jpg";
    String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
    resp.setHeader("Content-Disposition", "attachment;filename=" +fileName );//最重要的设置头,表明下载
    FileInputStream fis = new FileInputStream(realPath);
    ServletOutputStream os = resp.getOutputStream();//获取流去读写
    byte[] buffer = new byte[1024];
    int len ;
    while((len = fis.read(buffer))!=-1){
    os.write(len);
    }
    os.close();
    fis.close();

    }

2.重定向

  • 还是有ABC三个人,A想要获取信息,他一开始只能找到B,接着B告诉A他需要的信息是在C那边,然后A就去找C,重定向就相当于是A从B询问后找C的过程。

  • 用途:用户登录

  • 主要方法Send Redirect

    • public class Demo02 extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              resp.sendRedirect("/cf/demo03");//重定向的地址
              //实际实现就是设置新地址和新的状态码
          }
      }
      //注意:重定向时候需要注意重定向的路径地址,是不是要加上Application context的位置
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21

      - 特点:地址会发生变化

      ### 6.Request与前端的连接测试

      #### 6.1表单的简单提交

      - 利用jsp编写表单

      - ```jsp
      <html>
      <body>
      <h2>Hello World!</h2><br>
      <form action="${pageContext.request.contextPath}/demo06" method="get">
      用户名:<input type="text" name="username"> <br>
      密码 :<input type="password" name="password"><br>
      <input type="submit">
      </form>
      </body>
      </html>
      <%--${pageContext.request.contextPath}/demo06这个是用来与后端的服务器相连的信息,结果就会走demo06的网络路径 要提前导maven--%>
  • 编写对应的java后台服务

    • public class Demo06 extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              System.out.println("进入了这个服务");
              String username = req.getParameter("username");//获取username信息
              String password = req.getParameter("password");//获取password信息
              System.out.println(username+":"+password);
          }
      }
      //getParameter就是用来获取特定的字段中信息的具体内容的
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29

      ### 7.Cookies

      - 作用

      - 保存登录数据

      - 编写一个小的Cookie访问

      - ```java
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      resp.setContentType("text/html;charset = utf-8");//设置服务器返回编码
      Cookie[] cookies = req.getCookies();//先获取cookies
      PrintWriter writer = resp.getWriter();//浏览器输出
      boolean flag =false;
      for (Cookie cookie : cookies) {
      if (cookie.getName().equals("lastTime")){
      Long timer = Long.valueOf(cookie.getValue());//还原原来的日期格式
      Date date = new Date(timer);
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
      String currentTime = sdf.format(date);
      writer.write("你上一次访问本站的时间是:"+currentTime);
      flag =true;
      }
      }
      if (!flag) writer.write("这是你第一次访问,我们为您创建了cookie,方便下次访问");
      Cookie lastTime = new Cookie("lastTime", System.currentTimeMillis() + "");//Cookie都是以键值对的形式存在
      resp.addCookie(lastTime);
      }
  • 注销Cookie

    • 手动调用setMaxAge设置时间为0

8.Session

  • 作用:

    • 还是暂存用户信息,如登录信息,但是更强大,能存储整个类,同时存储容量上限也高
  • 编写一个存储person类的session例

    • person类

      • String name;
        int age ;
        //构造函数,get,set,tostring
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10

        - 创建Session的类

        - ```java
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset = utf-8");
        HttpSession session = req.getSession();
        session.setAttribute("username", new Person("借口",18));
        }
    • 得到session的类

      • protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            req.setCharacterEncoding("utf-8");
            resp.setContentType("text/html;charset = utf-8");
            HttpSession session = req.getSession();
            Person person = (Person) session.getAttribute("username");
            System.out.println(person);
            resp.getWriter().write(String.valueOf(person));
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11

        - 先调用第一个类,然后调用第二个类就可以获取到存储到整个类里的信息了

        - Session的注销

        - 调用`invalidate`方法手动注销

        - ```xml
        <session-config>
        <session-timeout>1</session-timeout><!--这里就是配置session的注销时间,以分钟为单位-->
        </session-config>
  • Session和Cookie的区别

    • Cookie是把用户的数据写给用户的浏览器,浏览器保存
    • Session把用户的数据写到用户独占Session中,服务器保存(保存重要的信息,减少服务器资源的浪费)
    • Session对象由服务创建

9.JSP

9.1Jsp语法

整个JSP的内容实际上是一个HTML,但是稍有不同:

  • 包含在<%----%>之间的是JSP的注释;
  • 包含在<%%>之间的是Java代码,可以编写任意Java代码;
  • 如果使用<%= xxx %>则可以快捷输出一个变量的值。
  • <%! %>可以写java代码(作用域更高的,相当于全局),称之为声明:会被编译到SP生成ava的类中!其他的,就会被生成到jspService方法中!

9.2定义跳转错误页面

1
2
3
4
<error-page>
<error-code>404</error-code><!--这里写错误的代码编号,不写的话所有错误页面都会跳转同一个地址-->
<location></location><!--发生错误时候跳转的地址-->
</error-page>

9.3包含相同的标签头和尾

1
<jsp:include page="index.jsp"/><%--这里就像人家的公安机关的声明,是重复可用的可以包含导入--%>

9.4内置9大对象

1
2
3
4
5
6
7
8
9
10
11
12
PageContext <%--存东西,级别最次--%>
Request <%--存东西,级别次--%>
Response
Session <%--存东西,级别中--%>
Application->SerlvetContext <%--存东西,级别高--%>
config->SerlvetConfig
out
page
exception
<%--一般存东西就setAttribute--%>
<%--取东西就getAttribute--%>
<%--输出东西就El表达式${},花括号里放输出的值--%>

9.5 jsp表达式标签

1
2
3
4
5
6
7
<%--  <jsp:include page=""/>--%>
<%-- <jsp:forward page=" "/>--%>
<jsp:forward page="jump.jsp">
<jsp:param name="name" value="real"/>
<jsp:param name="age" value="18"/>
</jsp:forward>
<%--包含页面,跳转页面,跳转页面带参数--%>

9.6Jstl常用

  • if,switch,set;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<form action="JstlTest01.jsp" method="get">
<input type="text" name="username" value="${param.username}"><%--这里的value需要写成el表达式,等同于req.getParameter--%>
<input type="submit" value="提交">
</form>
<c:if test="${param.username=='admin'}" var="isAdmin"><%--if判断值--%>
<c:out value="管理员欢迎"></c:out>
</c:if>
<c:out value="${isAdmin}"></c:out
<c:set var="score" value="85"></c:set><%--设置参数,键值对--%>
<c:choose>><%--类似switch--%>
<c:when test="${score>90}"><%--就像case--%>
你的成绩不错
</c:when>
</c:choose>

  • foreach
1
2
3
4
5
6
7
8
9
10
11
<%
//先创建ArrayList,通过req放入值
ArrayList<String> People = new ArrayList<>();
People.add(0,"0");
People.add(1,"1");
People.add(2,"2");
request.setAttribute("list",People);
%>
<c:forEach var="person" items="${list}"><%--定义变量,元素--%>
<c:out value="${person}"/><%--输出每次遍历的值--%>
</c:forEach>

10.Filter过滤器

  • 编写fileterDemo类,实现Fileter接口(是javax.servlet包下面的Fileter)

    • public class FilterDemo01 implements Filter {
          public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
              servletRequest.setCharacterEncoding("utf-8");//请求编码
              servletResponse.setContentType("text/html;charset = utf-8");//响应编码
              System.out.println("doFilter进入前面");
              filterChain.doFilter(servletRequest,servletResponse);//主要方法,看成一条链,传递原来的req和resp对象;
              System.out.println("doFilter进入后面");
          }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14

      - 配置web.xml

      - 由于注册servlet的xml中url-pattern可以对应多个地址,所以如果可以通过不同的url-pattern来验证

      - ```xml
      <filter>
      <filter-name>filterDemo</filter-name>
      <filter-class>com.LeiLei.Demo01.FilterDemo01</filter-class>
      </filter>
      <filter-mapping>
      <filter-name>filterDemo</filter-name>
      <url-pattern>/servlet/*</url-pattern>
      </filter-mapping>

11.Listener

  • 先实现HttpSessionListenerservlet监听器接口,重写方法;

    • public void sessionCreated(HttpSessionEvent se) {//创建方法
          ServletContext context = se.getSession().getServletContext();
          Integer onlineCnt = (Integer) context.getAttribute("onlineCnt");//获取onlineCnt的字段
          if (onlineCnt==null){
                  onlineCnt= 1;
              }else {
                  onlineCnt = onlineCnt+1;
              }
              context.setAttribute("onlineCnt",onlineCnt);//每次添加这字段
      }
      public void sessionDestroyed(HttpSessionEvent se) {//注销方法
              ServletContext context = se.getSession().getServletContext();
              Integer onlineCnt = (Integer) context.getAttribute("onlineCnt");
              if (onlineCnt==null){
                  onlineCnt= 0;
              }else {
                  onlineCnt = onlineCnt - 1;
              }
              context.setAttribute("onlineCnt",onlineCnt);
      }
      
      1
      2
      3
      4
      5
      6
      7
      8

      - 编写jsp与此类对应

      - ```jsp
      <body>
      <h1>当前的在线人数有<span style="color: lightblue"><%=this.getServletConfig().getServletContext().getAttribute("onlineCnt")%></span>人</h1>
      </body>
      <%--通过EL表达式拿到关联类的字段-%>

12.JBDC

12.1配置信息

1
2
3
String url = "jdbc:mysql://localhost:3306/test01?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC";
String username = "root";
String password = "root";

12.2加载驱动

1
Class.forName("com.mysql.cj.jdbc.Driver") ;

12.3连接数据库

1
Connection connection = DriverManager.getConnection(url, username, password);

12.4向数据库发送statement请求,CRUD

1
Statement statement = connection.createStatement();

前面这些步骤都是固定的,需要的时候改一改username,url,password

#### 12.5写sql
1
String sql  ="select *from person";

12.6执行sql

1
2
3
4
5
6
7
8
ResultSet res = statement.executeQuery(sql);
while (res.next()){//当结果接不空就执行
System.out.println("id:"+ res.getObject("id"));
System.out.println("name:"+ res.getObject("name"));
System.out.println("password:"+ res.getObject("password"));
System.out.println("email:"+ res.getObject("email"));
System.out.println("birthday:"+ res.getObject("birthday"));
}

12.7 关闭连接

  • 先开后关
1
2
3
res.close();
statement.close();
connection.close();

记录一个小问题

  • 关于idea的控制台里输出的内容的乱码问题(是指原来sout在控制台里的东西),需要在tomcat配置的时候的VM options里配置
1
-Dfile.encoding=UTF-8
  • 解决乱码
1
.setContentType("text/html;charset = utf-8");