Skip to main content
Jkyo Chen Blog

JSP&Servlet 学习笔记

Web应用程序简介 #

URL #

HTTP #

编写与设置servlet #

在HelloServlet之后 #

使用@WebServlet #

@WebServlet {
    name="Hello",
    urlPatterns={"/hello.view"},
    loadOnStartup=1
}

使用Web.xml #

<servlet>
	<servlet-name>HelloServlet</servlet-name>
	<servlet-class>cc.openhome.HelloServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>HelloServlet</servlet-name>
	<url-pattern>/helloUser.view</url-pattern>
</servlet-mapping>

文件组织与部署 #

进阶部署设置 #

URL模式设置 #

/FirstServlet/servlet/path.view = /FirstServlet + /servlet + /path.view

Web目录结构 #

使用web-fragment.xml #

  1. web-fragment.xml

    • 一个JAR文件中,除了可使用标注定义的Servlet,监听器,过滤器,还可以拥有自己的部署描述文件,这个文件的名称是web-fragment.xml,必须放置在JAR文件的META-INF目录中。
    • web-fragment.xml的根标签是而不是
    • 实际上,web-fragment.xml中所指定的类,不一定要在JAR文件中,也可以是子啊web应用程序的/WEB-INF/classes中。
  2. web.xml与web-fragment.xml

    • Servlet3.0对web.xml与标注的配置顺序并没有定义,对web-fragment.xml及标注的配置顺序也没有定义,然而可以决定web.xml与web-fragment.xml的配置顺序,其中一个设置方式实在web.xml中使用定义绝对顺序。

    • 另一个定义顺序的方式,是直接在每个JAR文件的web-fragment.xml中使用,其中使用来定义顺序。

  3. metadata-complete属性

    • 如果将web.xml中的metadata-complete属性设置为true(默认是false),则表示web.xml中已完成Web应用程序的相关定义,部署时将不会扫描标注与web-fragment.xml中的定义,如果有也会被忽略。

请求与响应 #

从容器到HttpServlet #

Web容器做了什么 #

关于HttpServletRequest #

处理请求参数与标头 #

取得请求参数 #

    String getParameter();

    String username = request.getParameter("name");
    // 若请求中没有所指定的参数名称,则返回null

    String[] getParameterValues();
    Enumeration getParameterNames();

    Enumeration e = req.getParameterNames();

    Map getParameterMap();
    // Map中的键是请求参数名称,值的部分是请求参数值,以字符串数组类型String[]返回(考虑有同一请求参数有多个值的情况)

获取HTTP的标头(Header)信息 #

    String getHeader();//指定标头名称后可返回字符串值,代表浏览器所送出的标头信息
    Enumeration getHeaders();//元素为字符串
    Enumeration getHeaderNames();//取得标头名称

    @Webservlet("/header.view")
    public class HeaderServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest res, HttpServletResponse resp) throws ServletException, IOException {
            PrintWriter out = resp.getWriter();
            out.println("");
            out.println("");
            out.println("HeaderServlet");
            out.println("");
            out.println("");
            out.println("

HeaderServlet at" + req.getContextPath() + "

"); Enumeration names = req.getHeaderNames(); while(names.hasMoreElements() { String name = names.nextElements(); out.println(name + ":" + req.getHeader(name) + "
"); } out.println(""); out.println(""); } } 标头值本身是个整数或日期的字符串表示法 getIntHeader() // 转换为int 失败则 抛出NumberFormatException getDateHeader() // 转换为Date 失败则抛出IllegalArgumentException

请求参数编码处理 #

POST请求参数编码处理 #

// 网页编码是UTF-8,相当于浏览器做了这个操作
String text = java.net.URLEncoder.encode("林", “UTF-8;“)

// 在Servlet中取得请求参数时,容器若默认使用ISO-8859-1来处理编码
String text = java.net.URLDecoder.decode("%E6%9E%97", "ISO-8859-1");

req.setCharacterEncoding("UTF-8");
// 指定取得POST请求参数时使用的编码

GET请求参数编码处理 #

getReader(), getInputStream()读取Body内容 #

getPart(), getParts() 取得上传文件 #

使用RequestDispatcher调派请求 #

使用include()方法 #

请求范围属性 #

forward()方法 #

@WebServlet("/hello.do");
public class HelloController extends HttpServlet {
	private HellModel model = new
	HelloModel();
	@override
	protected void doGet(HttpServletRequest request, HttpServletException response) throws ServletException, IOException {
		String name = request.getParameter("user");
		String message = model.doHello(name);
		request.setAttribute("message", message);
		request.getRequestDispatcher("hello.view").forward(request, response);
	}
}

......

public class HelloModel {
	private Map messages = new HashMap();
	public HelloModel() {
		messages.put("caterpillar", "Hello");
		messages.put("Justin", "Welcome");
		messages.put("momor", "Hi");
	}

	public String doHello(String user) {
		String message = messages.get(user);
		return message + ", " + user + "!";
	}
}

关于HttpServletResponse #

设置响应标头,缓冲区 #

试用getWriter()输出字符 #

使用getOutputStream()输出二进制字符 #

@WebServlet("/download.do")
public class Download extends HttpServlet {
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
		String passwd = request.getParameter("passwd");
		if("123455".equals(passwd)) {
			response.setContentType("application/pdf");
			InputStream in = getServletContent().getResourceAsStream("/WEB-INF/jdbc.pdf");
			outputStream out = response.getOutputStream();
			WriteBytes(in, out);
		}
	}

	private void writeBytes(InputStream in, OutputStream out) throws IOException {
		byte[] buffer = new byte[1024];
		int length = -1;
		while ((length = in.read(buffer)) != -1) {
			out.write(buffer, 0, length);
		}
		in.close();
		out.close();
	}
}

// 为了取得Web应用程序中的文件串流,可以使用HttpServlet的 getServletContext()取得ServletContext对象,这个对象代表了目前这个Web应用程序,可以使用ServletContext的getResourceAsStream()方法以串流程序读取文件,制定的路径要是相对于Web应用程序环境根目录

使用sendRedirect(), sendError() #

response.sendRedirect("http://openhome.cc");
// 这个方法会在响应中设置HTTP状态码301以及Location标头,浏览器接收到这个标头,会重新使用GET方法请求指定的URL,因此在地址栏上会发现URL的变更。
// 由于是利用HTTP状态码与标头信息,要求浏览器重定向网页,因此这个方法必须子在响应未确认输出前执行,否则会抛出IllegalStateException

// 处理请求的过程中发现一些错误,想要传递服务器默认的状态与错误信息
// 请求参数必须返回的资源根本不存在:
response.sendError(HttpServletResponse.SC_NOT_FOUND);
// SC_NOT_FOUND会令服务器响应404状态码,这类常数定义在HttpServletResponse接口上

// 自定义文字
response.sendError(HttpServletResponse.SC_NOT_FOUND, "笔记文件");
// HttpServlet的doGet()为例,其默认实现就使用了sendError()方法
// 在响应未确认输出前执行,否则会抛出IllegalStateException

综合练习 #

微博应用程序 #

复习 #

会话管理 #

会话基本原理 #

使用隐藏域 #

Cookie cookie = new Cookie("user", "caterpillar");
cookie.setMaxAge(7 * 24 * 60 * 60);// 单位是“秒”;
response.addCookie(cookie);
HTTPServletResponse getCookies();// 取得属于该网页所属域(Domain)的所有Cookie,返回值是Cookie[]数组。
Cookie[] cookies = request.getCookies();
if(cookies != null) {
    for(Cookie cookie : cookies) {
        String name = cookie.getName();
        String value = cookie.getValue();
        ...
    }
}
@WebServlet("/index.do")
public class Index extends HttpServlet {
	protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		Cookie[] cookies = request.getCookies();
		if(cookies != null) {
			for(Cookie cookie : cookies) {
				String name = cookie.getName();
				String value = cookie.getValue();
				if("user".equals(name) && "caterpillar".equals(value)) {
					request.setAttribute(name, value);
					request.getRequestDispatcher("/user.view").forward(request, response);
					return ;
				}
			}
		}
		response.sendRedirect("login.html");// 重定向到登录窗体
	}
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	processRequest(request, response);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	processRequest(request, response);
}
@WebServlet("/login.do")
public class Login extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	String user = request.getParameter("user");
    	String passwd = request.getParameter("passwd");
    	if("caterpillar".equals(user) && "123456".equals(passwd)) {
    		String login = request.getParameter("login");
    		if("auto".equals(login)) {
    			Cookie cookie = new Cookie("user", "caterpillar");
    			cookie.setMaxAge(7 * 24 * 60 * 60);
    			response.addCookie(cookie);
    		}
    		request.setAttribute("user", user);
    		request.getRequestDispatcher("user.view").forward(request, response);
    	}else {
    		response.sendRedirect("login.html");
    	}
    }
}

使用URL重写 #

@WebServlet("/search")
public class extends HttpServlet {

...
    String start = request.getParameter("start");
    if(start == null) {
    	start ="1";
    }
    int count = Integer.parseInt(start);
    int begin = 10 * count - 9;
    int end = 10 * count;
    out.println("第 " + begin + " 到 " + end + " 搜索结果
"); out.println("
    "); for(int i = 1; i <= 10 ; i++) { out.println("
  • 搜寻结果" + i + "
  • "); } out.println("
"); for(int i = 1; i < 10; i++) { if(i == count) { out.println(i); continue; } out.println("" + i + "

HttpSession会话管理 #

使用HttpSession #

HttpSession session = request.getSession();

// 另一个版本
// 传入布尔值,默认值时true,表示若尚未存在HttpSession实例时,直接创建一个对象。
// 若传入false,若尚未存在HttpSession实例,则直接返回null

HttpSession setAttribute() getAttribute()
// 这是存放属性对象的第二个地方
// 第三个地方是在ServletContext中

HttpSession会话管理原理 #

// HttpSession的 setMaxInactiveInterval()
// 设定浏览器多久没有请求应用程序的话,浏览器端的HttpSession对象就自动失效,设定的单位是秒。
// web.xml中设定失效时间的单位是分钟。
// 存储Session ID的Cookie默认为关闭浏览器就失效,,而且仅用于存储Session ID

	
		30
	

HttpSession与URL重写 #

综合练习 #

修改微博应用程序 #

Servlet进阶API,过滤器与监听器 #

Servlet进阶API #

Servlet, ServletConfig 与 GenericServlet #

使用ServletConfig #

@WebServlet(name="ServletOConfigDemo", urlPatterns={"/conf"},
		initParams={
			@WebInitParam(name = "PARAM1", value = "VALUE1"),
			@WebInitParam(name = "PARAM2", value = "VALUE2")
		}
)
public class ServletConfigDemo extends HttpServlet {
	private String PARAM1;
	private String PARAM2;
	public void init() throws ServletException {
		PARAM1 = getServletConfig().getInitParameter("PARAM1");
		PARAM2 = getServletConfig().getInitParameter("PARAM2");
	}
	...
}

OR


    ServletConfigDemo
    cc.openhome.ServletConfigDemo
    
        PARAM1
        VALUE1
    

// 若要用web.xml覆盖标注设置,web.xml的设置必须与@WebServlet的name属性相同

// GenericServlet将ServletConfig封装起来,便于取得设置信息
@WebServlet(name="ServletOConfigDemo", urlPatterns={"/conf"},
		initParams={
			@WebInitParam(name = "PARAM1", value = "VALUE1"),
			@WebInitParam(name = "PARAM2", value = "VALUE2")
		}
)
public class AddMessage extends HttpServlet {
	private String PARAM1;
	private String PARAM2;
	public void init() throws ServletException {
		PARAM1 = getInitParameter("PARAM1");
		PARAM2 = getInitParameter("PARAM2");
	}
	...
}

ServletContext #

应用程序事件,监听器 #

ServletContext事件,监听器 #

HttpSession事件,监听器 #

HttpServletRequest事件,监听器 #

过滤器 #

+ 可以真正运行Servlet的service()方法“前”与Servlet的service()方法运行&#39“后”中间进行实现 + 将服务需求设计为可抽换的元器件 + 在请求转发时应用过滤器

实现与设置过滤器 #

Filter filter = filterIterator.next();
if(filter != null) {
    filter.doFilter(request, response, this);
}else {
    targetServlet.service(request, response);
}
@WebFilter(filterName="performance", urlPattern={"/*"})
public class PerformanceFilter implements Filter {
	private FilterConfig config;

	@Override
	public void init(FilterConfig config) throws ServletException {
		this.config = config;
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		long begin = System.currentTimeMillis();
		chain.doFilter(request, response);
		config.getServletContext().log("Request process in " + (System.currentTimeMillis() - begin) + "milliseconds");
	}

	@Override
	public void destroy() {}
}
@WebFilter{
	filterName="some",
	urlPatterns={"/some"},
	dispatcherType={
		DispatcherType.FORWARD,
		DispatcherType.INCLUDE,
		DispatcherType.REQUEST,
		DispatcherType.ERROR,
		DispatcherType.ASYNC
	}
}
// 不设置dispatcherTypes,则认为REQUEST

请求封装器 #

响应过滤器 #

#JSP

从JSP到Servlet #

JSP生命周期 #

+ _jspInit(), _jspDestroy(), _jspService(),转移后重新定义。转译后的Servlet是继承自HttpJSPBase类,HttpJspBase类继承自HttpServlet + 自定义可以重新定义jspInit(), jspService, jspDestroy

Servlet至JSP的简单转换 #

指示元素 #

声明,Scriptlet与表达式元素 #

```JSP //声明(Declaration)元素 <%! 类成员声明或方法声明 %> // 转译成Servlet中的类成员或方法 //小心数据共享与线程安全的问题 //jspInit()方法,jspDestroy()的方法通过这个进行初始化操作

//Scriptlet元素 <% Java语句 %> //转译后为Servlet源代码_jspService()方法中的内容

// 表达式元素 <%= Java表达式 %> <%= new Date() %> // 表达式元素中不要加上分号(;) //转译Servlet out.print(new Date());//表达式中的内容会直接转译为out对象输出时的指定内容 ```

注释元素 #

隐式对象/隐式变量 #

错误处理 #

标准标签(Standard Tag) #

<jsp:include>, <jsp:forward>标签 #

<jsp:useBean>, <jsp:setProperty><jsp:getProperty>简介 #

深入<jsp:useBean>, <jsp:setProperty><jsp:getProperty> #

谈谈Model1 #

XML格式标签 #

表达式语言(EL) #

EL简介 #

<%
	String a = request.getParameter("a");
	String b = request.getParameter("b");
	out.println("a + b = " + (Integer.parseInt(a) + Integer.parseInt(b)));
%>

${param.a} + ${param.b} = ${param.a + param.b}
// param是EL隐式对象之一,表示用户的请求参数
//对于null值直接以空字符串加以显示

<%= ((HttpServletRequest) pageContext.getRequest()).getMethod() %>
${pageContext.request.method}

使用EL取得属性 #

```JSP

<jsp:property name="user" property="name">登录成功

${user.name>登录成功

// EL隐式对象指定范围来存取属性。 ```

缺页 #

EL运算符 #

<%= Util.length(request.getAttribute("someList))%>
${ util: length(requestScope.someList) }

复习 #

使用JSTL #

简介 #

核心标签库 #

流程处理标签 #


	

${param.name} 登录成功

登录成功

登录失败

// ,必须放在中 // 中可以有多个,遇到true就输出 ${message.name} ${message.text} // items属性可以是数组,Collection,Iterator,Enumeration,Map与字符串 //items指定的是Map //则设置给var的对象会是Map.Entry,这个对象有getKey()与getValue()方法,可以让你取得键与值 Key: ${item.key}
Value: ${item.value}
//items指定字符串,则必须是个以逗号区隔的值,会自动以逗号来切割字符串 ${token}
//自行指定切割依据,使用 ${token}

错误处理标签 #


	${param.a} + ${param.b} = ${param.a + param.b}


	
${error.message}
${error}

网页导入,重定向,URL处理标签 #

属性处理与输出标签 #

I18N兼容格式标签库 #

I18N基础 #

信息标签 #

<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>



//标签设置basename属性,设置的作用域是整个页面都有作用。如果额外有设置,则会以的设置为主。

地区标签 #

```JSP <fmt:setLocale value="zh-TW"/> // 调用HttpServletResponse的setLocale() <fmt:setBundle basename="hello"/>

<fmt:message key="cc.openhome.hello"/>

// 如果使用了setCharacterEncoding()或setContentType()时指定了charset,则setLocale()就会被忽略。 // fmt:requestEncoding设置编码,就会调用HttpServletRequest的setCharacterEncoding(),必须在取得任何请求参数之前使用

<% ResourceBundle zh_TW = ResourceBundle.getBundle("hello", new Locale("zh", "TW")); pageConetext.setAttribute("zh_TW", new LocalozationContext(zh_TW)); %> <fmt:message bundle="${zh_TW}" key="cc.openhome.hello"/>

// fmt:message标签有个bundle属性,可用以指定LocalizationContext对象,可以在创建LocalizationContext对象时指定ResourceBundle与Locale对象。 //共享Locale信息,可以使用fmt:setLocale标签,value属性上指定地区信息。 ```

格式标签 #

XML标签库 #

函数标签库 #

<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/function"%>
${fn:length(param.text)}

自定义标签 #

整合数据库 #

JDBC入门 #

JDBC简介 #

使用Statement,ResultSet #