1 Java Web 目录结构
目录
描述
/test1_war_exploded
Web应用根目录,存储 jsp 或 html 文件
/test1_war_exploded/WEB-INF
存放配置文件,不能直接访问
/test1_war_exploded/WEB-INF/classes
存放编译后的 class 文件
/test1_war_exploded/WEB-INF/lib
存放所需 jar 文件,如 JDBC 驱动的 jar 文件
web.xml:servlet 、servlet mapping 以及其他配置
编译 servlet 命令:
1 javac -sourcepath src -classpath D:\soft\server\apache-tomcat-9.0.37\lib\servlet-api.jar -d WEB-INF\classes src\mypack\DispatcherServlet.java
2 Servlet Servlet API 主要由两个 Java 包组成:javax.servlet
和 javax.servlet.http
。在 javax.servlet
中定义了 Servlet 接口以及相关通用接口和类。在 javax.servlet.http
主要定义了与 HTTP 协议相关的 HttpServlet 类、HttpServletRequest 接口和 HttpServletResponse 接口。
javax.servlet.Servlet
接口主要定义了servlet
基础生命周期方法:init(初始化)
、getServletConfig(配置)
、service(服务)
、destroy(销毁)
。
javax.servlet.http.HttpServlet
类继承于javax.servlet.GenericServlet
,而GenericServlet
又实现了javax.servlet.Servlet
和javax.servlet.ServletConfig
。而HttpServlet
不仅实现了servlet
的生命周期并通过封装service
方法抽象出了doGet/doPost/doDelete/doHead/doPut/doOptions/doTrace
方法用于处理来自客户端的不一样的请求方式,我们的Servlet只需要重写其中的请求方法或者重写service
方法即可实现servlet
请求处理。
TestServlet示例代码:
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 30 package com.anbai.sec.servlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;public class TestServlet extends HttpServlet { @Override protected void doGet (HttpServletRequest request, HttpServletResponse response) throws IOException { doPost(request, response); } @Override protected void doPost (HttpServletRequest request, HttpServletResponse response) throws IOException { PrintWriter out = response.getWriter(); out.println("Hello World~" ); out.flush(); out.close(); } }
2.1 配置 Servlet 的两种方式 (1)web.xml
1 2 3 4 5 6 7 8 9 <servlet > <servlet-name > dispatcher</servlet-name > <servlet-class > mypack.DispatcherServlet</servlet-class > </servlet > <servlet-mapping > <servlet-name > dispatcher</servlet-name > <url-pattern > /dispatcher</url-pattern > </servlet-mapping >
(2)使用 Annotation 标注
在 Servlet3.0 之后( Tomcat7+)可以使用注解方式配置 Servlet 了,在任意的Java类添加javax.servlet.annotation.WebServlet
注解即可。
1 2 3 4 5 …… import javax.servlet.annotation.*;@WebServlet (name="FontServlet1" , urlPatterns={"/font1" }, initParams={@WebInitParam (name="color" ,value="blue" ),@WebInitParam (name="size" ,value="15" )})public class FontServlet1 extends HttpServlet {……}
2.2 Request & Response HttpServletRequest 常用方法
方法
说明
getParameter(String name)
获取请求中的参数,该参数是由name指定的
getParameterValues(String name)
返回请求中的参数值,该参数值是由name指定的
getRealPath(String path)
获取Web资源目录
getAttribute(String name)
返回name指定的属性值
getAttributeNames()
返回当前请求的所有属性的名字集合
getCookies()
返回客户端发送的Cookie
getSession()
获取session回话对象
getInputStream()
获取请求主题的输入流
getReader()
获取请求主体的数据流
getMethod()
获取发送请求的方式,如GET、POST
getParameterNames()
获取请求中所有参数的名称
getRemoteAddr()
获取客户端的IP地址
getRemoteHost()
获取客户端名称
getServerPath()
获取请求的文件的路径
HttpServletResponse 常用方法
方法
说明
getWriter()
获取响应打印流对象
getOutputStream()
获取响应流对象
addCookie(Cookie cookie)
将指定的Cookie加入到当前的响应中
addHeader(String name,String value)
将指定的名字和值加入到响应的头信息中
sendError(int sc)
使用指定状态码发送一个错误到客户端
sendRedirect(String location)
发送一个临时的响应到客户端
setDateHeader(String name,long date)
将给出的名字和日期设置响应的头部
setHeader(String name,String value)
将给出的名字和值设置响应的头部
setStatus(int sc)
给当前响应设置状态码
setContentType(String ContentType)
设置响应的MIME类型
3 JSP 基础 3.1 JSP 指令 JSP 指令用来设置和整个网页相关的属性,如编码方式和脚本语言等
一般语法:
page 指令
指定所用的编程语言,与 JSP 对应的 servlet 接口,所拓展的类以及导入的软件包等
常用属性:https://www.cnblogs.com/sharpest/p/10068832.html
include 指令<%@ include file="filename" %>
包含其他文件(静态包含)
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
引入标签库的定义
3.2 JSP 声明 用于声明成员变量和方法
语法:<%! declaration;[declaration;]……%>
example:
1 2 3 4 5 6 7 8 9 <%! int v1=0 ;%> <%! String v5="hello" ; static int v6; %> <%! public String amethod (int i) { return i+1 ; } %>
3.3 Java 程序片段(Scriptlet) 在 JSP 文件中,可以在 <%
和 %>
标记间嵌入任何有效的 Java 程序代码。
3.4 JSP 表达式(EL) 传统 Java 表达式:<%=
和 %>
之间
https://www.jb51.net/article/105314.htm
3.5 JSP 九大隐含对象
变量名
类型
作用
pageContext
PageContext
当前页面共享数据,还可以获取其他8个内置对象
request
HttpServletRequest
客户端请求对象,包含了所有客户端请求信息
session
HttpSession
请求会话
application
ServletContext
全局对象,所有用户间共享数据
response
HttpServletResponse
响应对象,主要用于服务器端设置响应信息
page
Object
当前Servlet对象,this
out
JspWriter
输出对象,数据输出到页面上
config
ServletConfig
Servlet的配置对象
exception
Throwable
异常对象
3.6 JSP 标准标签库(JSTL) JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能。
JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签。 除了这些,它还提供了一个框架来使用集成JSTL的自定义标签。
https://www.runoob.com/jsp/jsp-jstl.html
4 JDBC JDBC连接数据库的一般步骤:
注册驱动,Class.forName("数据库驱动的类名")
。
获取连接,DriverManager.getConnection(xxx)
。
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 <!--首先导入一些必要的packages--> <%@ page import ="java.io.*" %> <%@ page import ="java.util.*" %> <!--告诉编译器使用SQL包--> <%@ page import ="java.sql.*" %> <!--设置中文输出--> <%@ page contentType="text/html; charset=GB2312" %> <html> <head> <title>dbaccess.jsp</title> </head> <body> <% try { Connection con; Statement stmt; ResultSet rs; Class.forName("com.mysql.jdbc.Driver" ); DriverManager.registerDriver(new com.mysql.jdbc.Driver()); String dbUrl = "jdbc:mysql://localhost:3306/BookDB?useUnicode=true&characterEncoding=GB2312&useSSL=false" ; String dbUser="root" ; String dbPwd="root" ; con = java.sql.DriverManager.getConnection(dbUrl,dbUser,dbPwd); stmt = con.createStatement(); stmt.executeUpdate("insert into BOOKS (ID,NAME,TITLE,PRICE) values('999','Tom','Tomcat Bible',44.5)" ); rs = stmt.executeQuery("select ID,NAME,TITLE,PRICE from BOOKS" ); out.println("<table border=1 width=400>" ); while (rs.next()){ String col1 = rs.getString(1 ); String col2 = rs.getString(2 ); String col3 = rs.getString(3 ); float col4 = rs.getFloat(4 ); out.println("<tr><td>" +col1+"</td><td>" +col2+"</td><td>" +col3+"</td><td>" +col4+"</td></tr>" ); } out.println("</table>" ); stmt.executeUpdate("delete from BOOKS where ID='999'" ); rs.close(); stmt.close(); con.close(); Enumeration<Driver> drivers = DriverManager.getDrivers(); while (drivers.hasMoreElements()) { DriverManager.deregisterDriver(drivers.nextElement()); } }catch (Exception e){out.println(e.getMessage());} %> </body> </html>
4.1 数据源(DataSource) 在真实的Java项目中通常不会使用原生的JDBC
的DriverManager
去连接数据库,而是使用数据源(javax.sql.DataSource
)来代替DriverManager
管理数据库的连接。一般情况下在Web服务启动时候会预先定义好数据源,有了数据源程序就不再需要编写任何数据库连接相关的代码了,直接引用DataSource
对象即可获取数据库连接了。
在 META-INF
目录下创建一个 content.xml
文件,在里面定义数据源
1 2 3 4 5 6 7 <Context reloadable ="true" > <Resource name ="jdbc/BookDB" auth ="Container" type ="javax.sql.DataSource" maxActive ="100" maxIdle ="30" maxWait ="10000" username ="root" password ="root" driverClassName ="com.mysql.jdbc.Driver" url ="jdbc:mysql://localhost:3306/BookDB?autoReconnect=true& useUnicode=true& characterEncoding=GB2312& useSSL=false" /> </Context >
web.xml
中加入 <resource-ref>
元素
1 2 3 4 5 6 <resource-ref > <description > DB Connection</description > <res-ref-name > jdbc/BookDB</res-ref-name > <res-type > javax.sql.DataSource</res-type > <res-auth > Container</res-auth > </resource-ref >
获取 jdbc/BookDB 数据源引用,并获取连接对象
1 2 3 4 5 Connection con; Context ctx = new InitialContext(); DataSource ds =(DataSource)ctx.lookup("java:comp/env/jdbc/BookDB" ); con = ds.getConnection();
example
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 <!--首先导入一些必要的包--> <%@ page import ="java.io.*" %> <%@ page import ="java.util.*" %> <%@ page import ="java.sql.*" %> <%@ page import ="javax.sql.*" %> <%@ page import ="javax.naming.*" %> <!--设置中文输出--> <%@ page contentType="text/html; charset=GB2312" %> <html> <head> <TITLE>dbaccess1.jsp</TITLE> </head> <body> <% try { Connection con; Statement stmt; ResultSet rs; Context ctx = new InitialContext(); DataSource ds =(DataSource)ctx.lookup("java:comp/env/jdbc/BookDB" ); con = ds.getConnection(); stmt = con.createStatement(); stmt.executeUpdate("insert into BOOKS(ID,NAME,TITLE,PRICE) values ('999','Tom','Tomcat Bible',44.5)" ); rs = stmt.executeQuery("select ID,NAME,TITLE,PRICE from BOOKS" ); out.println("<table border=1 width=400>" ); while (rs.next()){ String col1 = rs.getString(1 ); String col2 = rs.getString(2 ); String col3 = rs.getString(3 ); float col4 = rs.getFloat(4 ); out.println("<tr><td>" +col1+"</td><td>" +col2+"</td><td>" +col3+"</td><td>" +col4+"</td></tr>" ); } out.println("</table>" ); stmt.executeUpdate("delete from BOOKS where ID='999'" ); rs.close(); stmt.close(); con.close(); }catch (Exception e) {out.println(e.getMessage());e.printStackTrace();} %> </body> </html>
5 JavaBean JavaBean 是特殊的 Java 类,使用 Java 语言书写,并且遵守 JavaBean API 规范,是一种可重复使用、且跨平台的软件组件。
提供一个默认的无参构造函数。
需要被序列化并且实现了 Serializable 接口。
可能有一系列可读写属性。
可能有一系列的 getter 或 setter 方法。
JavaBean 示例
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 30 package mypack;public class StudentsBean implements java .io .Serializable { private String firstName = null ; private String lastName = null ; private int age = 0 ; public StudentsBean () { } public String getFirstName () { return firstName; } public String getLastName () { return lastName; } public int getAge () { return age; } public void setFirstName (String firstName) { this .firstName = firstName; } public void setLastName (String lastName) { this .lastName = lastName; } public void setAge (int age) { this .age = age; } }
编译后的 .class 文件存放在 /WEB_INF/classes/mypack/
中
导入 JavaBean 类
要想访问,首先需要导入:<%@ page import="mypack.StudentsBean"%>
声明 JavaBean 对象
使用 <jsp:useBean>
来声明:<jsp:useBean id="myBean" class="mypack.StudentsBean" scope="session"/>
<jsp:useBean>
属性:
id: 命名引用该Bean的变量。如果能够找到id和scope相同的Bean实例,jsp:useBean动作将使用已有的Bean实例而不是创建新的实例。
class: 指定Bean的完整包名
scope: 指定Bean在哪种上下文内可用,可以取下面的四个值之一:page,request,session和application
1 2 3 4 1. 默认值是page,表示该Bean只在当前页面内可用(保存在当前页面的PageContext内)。 2. request表示该Bean在当前的客户请求内有效(保存在ServletRequest对象内)。 3. session表示该Bean对当前HttpSession内的所有页面都有效。 4. application则表示该Bean对所有具有相同ServletContext的页面都有效。
type: 指定引用该对象的变量的类型,它必须是Bean类的名字、超类名字、该类所实现的接口名字之一。请记住变量的名字是由id属性指定的。
beanName: 指定Bean的名字。如果提供了type属性和beanName属性,允许省略class属性。
访问 JavaBean 属性
1)使用 <jsp:getProperty>
标签
1 <jsp:getProperty name="myBean" property="count" />
2)Java表达式
3)EL 表达式
给 JavaBean 属性赋值:
1 2 3 <jsp:setProperty name="myBean" property="count" value="1" /> 或 <% myBean.setCount(1 );%>
6 Filter javax.servlet.Filter
是Servlet2.3
新增的一个特性,主要用于过滤URL请求,通过Filter我们可以实现URL请求资源权限验证、用户登陆检测等功能。
Filter是一个接口,实现一个Filter只需要重写init
、doFilter
、destroy
方法即可,其中过滤逻辑都在doFilter
方法中实现。
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 package mypack;import java.io.*;import javax.servlet.*;import javax.servlet.http.*;import javax.servlet.annotation.*; public class NoteFilter implements Filter { private FilterConfig config = null ; private String blackList=null ; private String ipblock=null ; public void init (FilterConfig config) throws ServletException { System.out.println("NoteFilter: init()" ); this .config = config; ipblock=config.getInitParameter("ipblock" ); blackList=config.getInitParameter("blacklist" ); } public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("NoteFilter: doFilter()" ); if (!checkRemoteIP(request,response))return ; if (!checkUsername(request,response))return ; long before = System.currentTimeMillis(); config.getServletContext().log("NoteFilter:before call chain.doFilter()" ); chain.doFilter(request, response); config.getServletContext().log("NoteFilter:after call chain.doFilter()" ); long after = System.currentTimeMillis(); String name = "" ; if (request instanceof HttpServletRequest) { name = ((HttpServletRequest)request).getRequestURI(); } config.getServletContext().log("NoteFilter:" +name + ": " + (after - before) + "ms" ); } private boolean checkRemoteIP (ServletRequest request, ServletResponse response) throws IOException, ServletException { String addr=request.getRemoteAddr(); if (addr.indexOf(ipblock)==0 ){ response.setContentType("text/html;charset=GB2312" ); PrintWriter out = response.getWriter(); out.println("<h1>对不起,服务器无法为你提供服务。</h1>" ); out.flush(); return false ; }else { return true ; } } private boolean checkUsername (ServletRequest request, ServletResponse response) throws IOException, ServletException { String username =((HttpServletRequest) request).getParameter("username" ); if (username!=null ) username=new String(username.getBytes("ISO-8859-1" ),"GB2312" ); if (username!=null && username.indexOf(blackList) != -1 ) { response.setContentType("text/html;charset=GB2312" ); PrintWriter out = response.getWriter(); out.println("<h1>对不起," +username + ",你没有权限留言 </h1>" ); out.flush(); return false ; }else { return true ; } } public void destroy () { System.out.println("NoteFilter: destroy()" ); config = null ; } }
Filter
的配置类似于Servlet
,由<filter>
和<filter-mapping>
两组标签组成,如果Servlet版本大于3.0同样可以使用注解的方式配置Filter
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <filter > <filter-name > NoteFilter</filter-name > <filter-class > mypack.NoteFilter</filter-class > <init-param > <param-name > ipblock</param-name > <param-value > 221.45</param-value > </init-param > <init-param > <param-name > blacklist</param-name > <param-value > 捣蛋鬼</param-value > </init-param > </filter >
使用 @WebFilter
标注
1 2 3 4 5 6 7 8 @WebFilter ( filterName = "NoteFilter" , urlPatterns = "/note" , initParams = { @WebInitParam (name = "ipblock" , value = "221.45" ), @WebInitParam (name = "blacklist" , value = "捣蛋鬼" )}) public class NoteFilter implements Filter {
Filter和Servlet的总结:https://javasec.org/javaweb/Filter&Servlet/
7 序列化 8 XML 9 MVC 设计模式 spring MVC 工作流程
用户向服务端发送一次请求,这个请求会先到前端控制器DispatcherServlet(也叫中央控制器)。
DispatcherServlet接收到请求后会调用HandlerMapping处理器映射器。由此得知,该请求该由哪个Controller来处理(并未调用Controller,只是得知)
DispatcherServlet调用HandlerAdapter处理器适配器,告诉处理器适配器应该要去执行哪个Controller
HandlerAdapter处理器适配器去执行Controller并得到ModelAndView(数据和视图),并层层返回给DispatcherServlet
DispatcherServlet将ModelAndView交给ViewReslover视图解析器解析,然后返回真正的视图。
DispatcherServlet将模型数据填充到视图中
DispatcherServlet将结果响应给用户
lib 文件夹中必须包含 Spring 软件包的依赖
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?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_4_0.xsd" version ="4.0" > <display-name > Spring MVC Sample</display-name > <servlet > <servlet-name > HelloWeb</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet </servlet-class > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > HelloWeb</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > </web-app >
为 DispatcherServlet 映射的URL为”/“,所有访问应用的用户都会由 DispatcherServlet 来预处理,然后再由它转发给后续组件。为 DispatcherServlet 设置的 Servlet 名字为 “HelloWeb”,即必须为 Spring MVC 提供一个名为 HelloWeb-servlet.xml 的配置文件。
HelloWeb-servlet.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <beans xmlns = "http://www.springframework.org/schema/beans" xmlns:context = "http://www.springframework.org/schema/context" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" > <context:component-scan base-package = "mypack" /> <bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name = "prefix" value = "/WEB-INF/jsp/" /> <property name = "suffix" value = ".jsp" /> </bean > </beans >
指定解析视图组件的为 InternalResourceViewResolver ,prefix 和 suffix 属性分别设定了视图文件的前缀和后缀。
参考