1. 程式人生 > >看視訊自學Servlet

看視訊自學Servlet

(一)如何建立一個Servlet

1.繼承 GenericServlet

程式碼:

public class ServletDemo1 extends GenericServlet{

	@Override
	public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
		
		res.getOutputStream().write("Hello servlet!".getBytes());
	}
}

web.xml中配置

  <servlet>
    <servlet-name>ServletDemo1</servlet-name>
    <servlet-class>com.boom.servlet.ServletDemo1</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>ServletDemo1</servlet-name>
    <url-pattern>/ServletDemo1</url-pattern>
  </servlet-mapping>

2.繼承 HttpServlet

程式碼:

public class ServletDemo2 extends HttpServlet {
 
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.getOutputStream().write("Hello HttpServlet!".getBytes());
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

web.xml

  <servlet>
    <description></description>
    <display-name>ServletDemo2</display-name>
    <servlet-name>ServletDemo2</servlet-name>
    <servlet-class>com.boom.servlet.ServletDemo2</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ServletDemo2</servlet-name>
    <url-pattern>/ServletDemo2</url-pattern>
  </servlet-mapping>
(二)用new 鍵 新建Servlet 包含(init方法,destory方法),web.xml檔案就不需要配置了

程式碼:

public class ServletDemo3 extends HttpServlet {
	//servlet  方法只 呼叫一次
	@Override
	public void init() throws ServletException { 
		// TODO Auto-generated method stub
		super.init();
		System.out.println("init");
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.getOutputStream().write("Hello HttpServlet!".getBytes());
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}
	
	@Override
	public void destroy() {
	System.out.println("destroy");
	}
}

web.xml不用配置了

(三)執行緒安全問題
1.靜態變數的使用導致執行緒安全問題,靜態變數儘量少使用

程式碼:

/**
 * 執行緒安全出現在多個執行緒操作同一資源上,就是靜態的使用要慎重
 * @author Boom
 *
 */
public class Person {
	//如果不是靜態變數的時候,當多個執行緒使用時用到的age是不同的,不會有執行緒安全
	public int age;
	
	//如果是靜態變數,因為靜態變數在類載入的時候都會建立,每個執行緒都是用到同一個物件,當同一個物件被多個執行緒使用時,就會產生執行緒併發事件
	// public static int age;
	
	//在開發中,用靜態要小心,可能會造成記憶體奔潰
	public List list = new ArrayList();
	//public static List list = new ArrayList();
}
/**
 * 執行緒安全
 * @author Boom
 *
 */
public class Demo {
	//假設100個執行緒跑這個方法,看age的狀態
	public static void main(String[] args) {
		Person person = new Person();	
		person.age++;
		//person.list.add("aaa");
		System.out.println(person.age);
	}	
}

2.實現SingleThreadModel介面解決執行緒安全問題

程式碼:

/**
 * 在web開發中,我們不用同步程式碼塊去解決併發事件,而是通過實現一個介面SingleThreadModel(不太建議),就是打個標記
 * 這種介面叫做標記介面,同理的有序列化介面,就是標記這個類有特權
 * @author Boom
 *	Servlet就像一個網頁,當出錯了,我們就要抓起來
 */
public class ServletDemo5 extends HttpServlet implements SingleThreadModel {
	/**
	 * 執行緒安全問題
	 */
	//在這裡初始化資料會出現併發事件
	int i=0; 
	//子類在覆蓋父類的方法,不能丟擲比父類更多的異常 (子類要比父類強,形象的說就是父親做東西丟擲了異常,子類又要比父類強我們就不能在子類拋更多的異常)
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		i++;
		try {
			Thread.sleep(1000*4);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//String.getBytes(); 把字串輸入到位元組流中
		response.getOutputStream().write((i+"").getBytes());
		
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

3.用同步程式碼塊synchronized(this){}解決執行緒安全問題

程式碼:

public class ServletDemo4 extends HttpServlet {
	/**
	 * 執行緒安全問題
	 */
	int i=0; 
	//在這裡初始化資料會出現併發事件
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//假設100個人同時操作這個dOGet()方法 ,會不會出現併發問題
		//在方法內部定義初始化不會出現執行緒併發事件
		//int i=0;
		//同步程式碼塊,單執行緒執行
		//用執行緒鎖解決執行緒併發問題,但是這種方法不行,如果一個執行緒正在訪問一個資源,而另一個也要等第一個執行緒訪問完才執行獲取資源
		synchronized(this){	
		i++;
		try {
			Thread.sleep(1000*4);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//String.getBytes(); 把字串輸入到位元組流中
		response.getOutputStream().write((i+"").getBytes());
		}
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

(四)ServletConfig

/**
 * ServletConfig
 * 在配置檔案中定義資料,在java中獲取(使用情況:在實際開發中,有些資料不適合在servlet中寫死,這類資料就可以通過配置方式配置給servlet,
 * 例如:servlet採用哪個碼錶,servlet連線哪個庫,servlet就配置哪個配置檔案)
 * @author Boom
 *  其實,struts就是一個特殊的servlet
 */
public class ServletDemo6 extends HttpServlet {

	//方法一
/*    private ServletConfig servletConfig;
    
    @Override
    public void init(ServletConfig config) throws ServletException {
    	this.servletConfig=config;
    	String value = servletConfig.getInitParameter("data");
    	System.out.println(value);
    }*/
    
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		//String value = servletConfig.getInitParameter("data");  方法一
		//方法二
		String value = this.getServletConfig().getInitParameter("data");//得到指定的
		Enumeration em = this.getServletConfig().getInitParameterNames();
		while (em.hasMoreElements()) {
			String name = (String) em.nextElement();
			String value1 =	this.getServletConfig().getInitParameter(name);
			System.out.println(name+"="+value);
		}
		
    	System.out.println(value);
		response.getOutputStream().write("Hello HttpServlet!".getBytes());
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}
	
	
}

(五)ServletContext

/**
 * ServletContext 以及ServletDemo8 多個servlet之間傳值(相當於聊天室)示例
 * @author Boom
 * ServletContext說的就是整個應用程式的範圍  在多個servlet中共享資料
 */
public class ServletDemo7 extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		//得到ServletContext的方式一:
		ServletContext	context = this.getServletConfig().getServletContext();
		//得到ServletContext的方式二:	
		//ServletContext	context1 = this.getServletContext();	
		String data="aaa";
		context.setAttribute("data",data);
	}


	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	
		doGet(request, response);
	}

}

(六)使用ServletContext 多個servlet之間傳值

/**
 * 多個servlet之間傳值(相當於聊天室)
 * @author Boom
 * 
 */
public class ServletDemo8 extends HttpServlet {


	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	//應用場景  之前給每個servlet都配置資料連線,我們可以直接通過context域配置資料庫連線
	String value1 =this.getServletContext().getInitParameter("data1");
	
	String value = (String) this.getServletContext().getAttribute("data");
	System.out.println(value);
	}

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

(七)Servlet中不適合對資料進行輸出,我們要應用Servlet的轉發

	/**
	 * Servlet中不適合對資料進行輸出,我們要應用Servlet的轉發
	 * @author Boom
	 * ServletDemo9和ServletDemo10
	 */

public class ServletDemo9 extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String value =this.getServletContext().getInitParameter("data1");
		//Servlet資料輸出比較麻煩,我們通過轉發來實現  讓jsp實現
		// servlet的重定向是讓他自己去做
		// Servlet的轉發是讓我來幫他找人做
		response.getOutputStream().write(("<font color='red'>"+value+"</font>").getBytes());
	}

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

}

(八)同過servletcontext實現請求轉發,每個web應用都有一個servletcontext

/**
 * 同過servletcontext實現請求轉發,每個web應用都有一個servletcontext
 * Servlet的轉發 ServletDemo9和ServletDemo10
 * @author Boom
 * 轉發物件     RequestDispatcher
 */
public class ServletDemo10 extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	
		String data="aaaaa";
		this.getServletContext().setAttribute("dt", data);  //不能放在context域中,為什麼呢?(涉及多執行緒問題,就是用的是同一物件,會覆蓋資料)
		//把資料放到context域物件中,並轉發給jsp去實現介面
		RequestDispatcher rd= this.getServletContext().getRequestDispatcher("/1.jsp");
		rd.forward(request, response);
	}


	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	
		doGet(request, response);
	}

}

(九)讀取資原始檔 

1.通過ServletContext訪問資原始檔 db.propertis

/**
 * 讀取資原始檔 通過ServletContext訪問資原始檔 db.propertis
 * 
 * @author Boom
 *
 */

public class ServletDemo11 extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		test5();
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

	//在專案的相對路徑src下新建db.properties檔案
	public void test1() throws IOException {
		InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
		// 固定套路 (把流輸出到properties中)
		Properties properties = new Properties();
		properties.load(in);

		String url = properties.getProperty("url");
		String username = properties.getProperty("username");
		String password = properties.getProperty("password");
		System.out.println(url);
		System.out.println(username);
		System.out.println(password);
	}
	//在com.boom.thread包下新建db.properties檔案
	public void test2() throws IOException {
		InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/boom/thread/db.properties");
		// 固定套路 (把流輸出到properties中)
		Properties properties = new Properties();
		properties.load(in);

		String url = properties.getProperty("url");
		String username = properties.getProperty("username");
		String password = properties.getProperty("password");
		System.out.println(url);
		System.out.println(username);
		System.out.println(password);
	}
	
	//在WEB-INF下新建db.properties檔案
	public void test3() throws IOException {
		InputStream in = this.getServletContext().getResourceAsStream("/db.properties");
		// 固定套路 (把流輸出到properties中)
		Properties properties = new Properties();
		properties.load(in);

		String url = properties.getProperty("url");
		String username = properties.getProperty("username");
		String password = properties.getProperty("password");
		System.out.println(url);
		System.out.println(username);
		System.out.println(password);
	}
	
	//讀取資原始檔需要注意的問題(但是我們得在tomcat的bin檔案考入檔案db.properties,才能實現)  最好採用servletcontext來讀取資原始檔
	public void test4() throws IOException {
		FileInputStream in = new FileInputStream("classes/db.properties");
		// 固定套路 (把流輸出到properties中)
		Properties properties = new Properties();  //map
		properties.load(in);
		String url = properties.getProperty("url");
		String username = properties.getProperty("username");
		String password = properties.getProperty("password");
		System.out.println(url);
		System.out.println(username);
		System.out.println(password);
	}
	
	public void test5() throws IOException{
		String path = this.getServletContext().getRealPath("/WEB-INF/classes/db.properties");
		String filename=path.substring(path.lastIndexOf("\\")+1);
		System.out.println(filename);
		FileInputStream in=new FileInputStream(path);
		// 固定套路 (把流輸出到properties中)
				Properties properties = new Properties();  //map
				properties.load(in);
				String url = properties.getProperty("url");
				String username = properties.getProperty("username");
				String password = properties.getProperty("password");
				System.out.println(url);
				System.out.println(username);
				System.out.println(password);	
	}
	
}

2.如果讀取資原始檔的程式不是servlet的話,就只能通過類載入器去讀了

程式碼:

新建一個UserDao

/**
 * 類裝載器
 * 如果讀取資原始檔的程式不是servlet的話,就只能通過類裝載器去讀了
 * @author Boom
 *
 */
public class UserDao {
	//把東西放到預編譯中,在類載入時就生成了,而且只有一次
	private static Properties dbconfig = new Properties();
	static{
		try {
		//針對如果修改了配置檔案中的資料,檢視執行後的輸出  方案一:無論檔案中怎麼改還是原來的
		//以下程式碼雖然可以讀取資原始檔的資料,但是無法獲取更新後的資料
		InputStream in = UserDao.class.getClassLoader().getResourceAsStream("db.properties");
		//方案二:修改後,資料也跟著修改了
		//String path = UserDao.class.getClassLoader().getResource("db.properties").getPath();
		//FileInputStream inputStream  = new FileInputStream(path); 
		//獲取檔案中的東西
		dbconfig.load(in);
		} catch (IOException e) {
		//拋一個初始化錯誤
			throw new ExceptionInInitializerError(e);
		}	
	}
	
	//不能傳入一個servletcontext物件,避免耦合
	public void update() throws IOException {
		System.out.println(dbconfig.getProperty("url"));
		System.out.println(dbconfig.getProperty("username"));
		System.out.println(dbconfig.getProperty("password"));
	}
	
	public void find(){
		
	}
	
	public void delete(){
		
	}
	
	/**
	 * 總結:讀取資原始檔
	 * 1.在servlet中,我們可以通過servletcontext去讀取資原始檔的資料
	 * 2.在其他類中,我們需要通過類載入器去讀取資原始檔的資料
	 * 
	 */
}

新建測試類

/**
 * 如果讀取資原始檔的程式不是servlet的話,就只能通過類載入器去讀了
 * @author Boom
 *
 */
public class ServletDemo12 extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		UserDao userdao =new UserDao();
		userdao.update();
	}

	
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		doGet(request, response);
	}

}