一、Servlet介紹
Servlet簡單的說就是一個Java程序,目的和Javabean差不多,爲了使得JSP頁面中代碼簡潔、清晰;
JavaBean不需要配置,只需要放在WEB-INF/classes中即可;
Servlet也是放在 WEB-INF/classes/中,並在web.xml中配置如下形式:
- <servlet>
- <servlet-name></servlet-name>
- <servlet-class></servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name></servlet-name>
- <url-pattern></url-pattern>
- </servlet-mapping>
如果需要設置配置信息,則需要形式如下:
- <servlet>
- <servlet-name></servlet-name>
- <servlet-class></servlet-class>
- <init-param>
- <param-name></param-name>
- <param-value></param-value>
- </init-param>
- </servlet>
- <servlet-mapping>
- <servlet-name></servlet-name>
- <url-pattern></url-pattern>
- </servlet-mapping>
注意:在url-pattern中,主目錄爲:"/",而不是"\"!
Servlet可以處理客戶端傳來的請求,即request,並且可以返回給客戶端迴應,即response,這個操作通過
(1)public void service(ServletRequest req,ServletResponse resp)throws ServletExeption,IOException{}
(2)public void doGet(HttpServletRequest req,HttpServletResponse resp)throws ServletExeption,IOException{}
(3)public void doPost(HttpServletRequest req,HttpServletResponse resp)throws ServletExeption,IOException{}
完成;
這裏需要注意的是service的參數只是ServletRequest,而其他兩個函數的參數是HttpServletRequest;
一般如果我們要自定義Servlet,則需要繼承HttpServlet類,並覆蓋相應的方法即可;
二、Servlet的結構
Servlet生命週期爲:加載-->初始化--->服務--->銷燬--->卸載;
加載:web容器加載Servlet,即創建一個Servlet實例;
初始化:調用servlet的init方法,爲了完成一些預備動作;
當請求到來時,
服務:創建一個request、response對象,並創建一個線程,調用類service方法;
銷燬:調用destroy()方法;當一個Servlet對象長時間不使用或web容器(tomcat)關閉時調用;
卸載:即退出;
繼承HttpServlet後,可以覆寫以下方法:
1.public void init(ServletConfig config)throws ServletException{} //初始化Servlet,(1)當需要使用Servlet時調用;(2)如果在web.xml中配置,則可以web容器啓動時自動加載;配置如下:
- <serlvet>
- <serlvet-name></servlet-name>
- <servlet-class></servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
2.public void init(ServletConfig config)throws ServletExeption{} //初始化Servlet,可以得到配置信息
3.public void doGet(HttpServletRequest req,HttpServletResponse resp)throws ServletExeption,IOException{} 當get方式傳遞,則調用此方法
4.public void doPost(HttpServletRequest req,HttpServletResponse resp)throws ServletExeption,IOException{}當post方法傳遞,則調用此方法
5.public void service(HttpServletRequest req,HttpServletResponse resp)throws ServletExeption,IOException{}
6.public void destroy(){} //銷燬時調用
注意:
1. 當1,2同時出現時,2有較高優先級;
2. 當3或4和5同時出現時,5具有較高優先級;
3 .PrintWriter writer = resp.getWriter();可以獲得輸出流;
注意:writer輸出時需要輸出HTML結構;
三、Servlet常見問題
1.在init方法中,通過config.getInitParameter()方法取得配置信息;
2.req.getSession():取得Session對象;
3.super.getServletContext();取得application對象;因爲GenericServlet中有getServletContext方法;
4.resp.getWriter()返回一個PrintWriter用以輸出文本數據、resp.getOutputStream()輸出二進制數據,並且兩者不能同時調用;
5.在init(ServletConfig config)方法中需要調用super.init(config);
6. 在service()方法中getServletConfig()返回 ServletConfig;
四、Servlet跳轉
1.客戶端跳轉:resp.sendRedirect("1.jsp") ; //類似於內置對象中的跳轉;
2.服務器跳轉:req.getRequestDispatcher("/hello.jsp").forward(req,resp);能夠跳轉到hello.jsp中;
注意:客戶端跳轉和服務器端跳轉的區別;
注意:這裏的getRequestDispatcher中的網頁一定要加“ / ”
五、MVC設計模式
在之前我們講過JSP+JAVABEAN的DAO開發模式,這個適用於小型開發;
MVC最早是由SmallTalk提出的;
Controller: Servlet 負責接收客戶請求並轉發給Model;
Model :JavaBean 負責真正處理業務邏輯;
View:JSP 負責輸出結果;
EJB(Enterprise JavaBean);
MVC(Model View Control)是一種以Servlet爲核心的開發模式,流程如下:
步驟如下:
1.客戶端發送請求給Servlet;
2.Servlet接收請求後處理,並可以調用JavaBean(即進行數據庫操作,並返回結果);
3.Servlet返回結果給JSP顯示;(通過設置request屬性後調用RequestDispatcher方法跳轉,並在JSP頁面中接收request屬性);
因此JSP只是用於顯示,而JavaBean只和Servlet通信;
注意:在MVC中,使用requestDispatcher的機會很多,我們都是通過這個類進行服務器跳轉的;
六、MVC實例
功能:登錄功能
1.JavaBean部分
User.java
- package org.vo;
- public class User{
- private String id;
- private String name;
- private String password;
- public String getId(){
- return id;
- }
- public void setId(String id){
- this.id = id;
- }
- public String getName(){
- return name;
- }
- public void setName(String name){
- this.name = name;
- }
- public void setPassword(String password){
- this.password = password;
- }
- public String getPassword(){
- return password;
- }
- }
IUserDAO.java
- package org.dao;
- import org.vo.*;
- public interface IUserDAO{
- public boolean findLogin(User user)throws Exception;
- }
- package org.dao.impl;
- import java.sql.*;
- import org.vo.*;
- import org.dao.*;
- public class UserDAOImpl implements IUserDAO{
- private Connection con;
- public UserDAOImpl(Connection con){
- this.con = con;
- }
- public boolean findLogin(User user)throws Exception{
- boolean flag = false;
- String sql = "SELECT name FROM user WHERE id=? AND password=?";
- PreparedStatement stat = con.prepareStatement(sql);
- stat.setString(1,user.getId());
- stat.setString(2,user.getPassword());
- ResultSet rs = stat.executeQuery();
- if(rs.next()){
- user.setName(rs.getString(1));
- flag = true;
- }
- return flag;
- }
- }
UserDAOProxy.java
- package org.dao.proxy;
- import org.dao.*;
- import org.vo.*;
- import org.dao.impl.*;
- import org.dbc.*;
- public class UserDAOProxy implements IUserDAO{
- private DatabaseConnection dbc;
- private IUserDAO idao;
- public UserDAOProxy(){
- dbc = new DatabaseConnection();
- idao = new UserDAOImpl(dbc.getConnection());
- }
- public boolean findLogin(User user)throws Exception{
- if(user==null){
- return false;
- }
- boolean flag = idao.findLogin(user);
- dbc.close();
- return flag;
- }
- }
DatabaseConnection.java
- package org.dbc;
- import java.sql.*;
- public class DatabaseConnection{
- public static final String DRIVER = "com.mysql.jdbc.Driver";
- public static final String URL = "jdbc:mysql://localhost:3306/mldn";
- public static final String USER = "root";
- public static final String PASS = "123456";
- private Connection con;
- public DatabaseConnection(){
- try{
- Class.forName(DRIVER);
- con = DriverManager.getConnection(URL,USER,PASS);
- }
- catch(Exception e){}
- }
- public Connection getConnection(){
- return con;
- }
- public void close(){
- try{
- if(con!=null){
- con.close();
- }
- }
- catch(Exception e){}
- }
- }
DAOFactory.java
- package org.factory;
- import org.dao.*;
- import org.dao.proxy.*;
- public class DAOFactory{
- public static IUserDAO getInstance(){
- return new UserDAOProxy();
- }
- }
以上代碼是JavaBean部分;MVC的特點是用Servlet調用JavaBean,而不是JSP調用JavaBean;
2.Servlet部分
以下是Servlet部分:Servlet是接收客戶端請求,並調用JavaBean進行數據庫操作;並把結果通過設置request屬性傳給JSP進行顯示;(貫穿核心)
LoginServlet.java
- package org.servlet;
- import java.util.*;
- import javax.servlet.*;
- import javax.servlet.http.*;
- import org.factory.*;
- import org.vo.*;
- import java.io.*;
- public class LoginServlet extends HttpServlet{
- public void doGet(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{
- String path = "login.jsp";
- String id = req.getParameter("id");
- String pass = req.getParameter("pass");
- List<String> info = new ArrayList<String>();
- if(id==null||"".equals(id)){
- info.add("id不能爲空");
- }
- if(pass==null||"".equals(pass)){
- info.add("密碼不能爲空");
- }
- if(info.size()==0){
- User user = new User();
- user.setId(id);
- user.setPassword(pass);
- try{
- if(DAOFactory.getInstance().findLogin(user)==true){
- info.add("歡迎光臨");
- }
- else{
- info.add("錯誤的用戶名和密碼");
- }
- }
- catch(Exception e){}
- }
- req.setAttribute("info",info);
- req.getRequestDispatcher(path).forward(req,resp);
- }
- public void doPost(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{
- this.doGet(req,resp);
- }
- }
Login.jsp
- <%@page contentType="text/html" pageEncoding="GBK" import="java.util.*"%>
- <html>
- <head>
- <title>A</title>
- </head>
- <script language="Javascript">
- function validate(f){
- if(!(/^\w{5,15}$/.test(f.id.value))){
- alert("id長度不對");
- f.id.focus();
- return false;
- }
- if(!(/^\w{5,15}$/.test(f.pass.value))){
- alert("密碼長度不對");
- f.pass.focus();
- return false;
- }
- return true;
- }
- </script>
- <body>
- <h2>用戶登錄程序</h2>
- <%
- request.setCharacterEncoding("GBK");
- List<String> info = (List<String>)request.getAttribute("info");
- if(info!=null){
- Iterator<String>iter = info.iterator();
- while(iter.hasNext()){
- %>
- <h4><%=iter.next()%></h4>
- <%
- }
- }
- %>
- <form action="LoginServlet" method="post" onSubmit="return validate(this)">
- 用戶ID:<input type="text" name="id"/><br />
- 密碼:<input type="password" name="pass"/><br />
- <input type="submit" value="提交"/>
- </form>
- </body>
- </html>
數據庫腳本:
- CREATE TABLE user(
- id varchar(30) PRIMARY KEY,
- name varchar(30) ,
- password varchar(30)
- );
- INSERT INTO user VALUES('XIAZDONG','xiazdong','12345');
因此最後再強調一下Mode1和Mode2的區別:
Mode1是通過JSP調用JavaBean;Mode2是通過Servlet調用JavaBean;
Mode1在JSP中仍然有處理的部分,而Mode2中JSP只負責顯示;
補充:Servlet調用過程順序圖
ServletContext介紹
- <context-param>
- <param-name></param-name>
- <param-value></param-value>
- </context-param>
- context.getRequestDispatcher("/1.html").forward(request,response);
- InputStream in = context.getResourceAsStream("*.properties");
- Properties props = new Properties();
- props.load(in);
補充:web開發中地址書寫問題
地址書寫時常用到“/”開頭,而“/”有兩個宗旨:
1.面向瀏覽器,則"/"表示http://localhost:8080/
2.面向服務器,則"/"表示當前web應用;
面向瀏覽器的意思是:是否會讓瀏覽器地址欄改變;其餘的都是面向服務器;
2.response.sendRedirect("地址B");
補充:在提供客戶發出請求之前的過程
1.從web.xml中讀出Servlet初始化參數和上下文初始化參數;
2.創建一個ServletConfig對象和ServletContext對象;
3.將Servlet初始化參數的引用賦給ServletConfig對象,把上下文初始化參數賦值給ServletContext對象;
4.創建ServletContextListener監聽器實例;
5.調用contextInitialized()方法;
6.創建這個Servlet實例;
7.調用init方法;
注意:
(1)在Servlet構造函數中還沒有ServletConfig對象,雖然能夠調用getServletConfig()方法;
(2)ServletConfig對象在Servlet實例創建之前就已經創建;
(3)web.xml的初始化參數只會讀一次,如果需要更新,則需要重新部署;
上下文初始化參數:整個web應用都能夠訪問的初始化參數;
<context-param>
<param-name>name</param-name>
<param-value>value</param-value>
</context-param>
getServletContext().getInitParameter("name")即可;
每個Servlet有一個ServletConfig,每個web應用有一個ServletContext;
如果web應用時分佈式的,則每個JVM都有一個ServletContext;
注意:getAttribute()返回的是Object;
Person p = getServletContext().getAttribute("person");是錯誤的!!!!!!!!!!!!!!!!!!!!!
Person p = (Person)getServletContext().getAttribute("person");是正確的;