(一)如何创建一个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);
}
}