public class HelloServlet implements Servlet {
//在Servlet类实例化后自动执行的方法,这个方法在servlet对象的整个生命周期中运行且只运
行一次。主要用于实现Servlet的初始化操作,例如读取配置文件中当前Servlet的初始化配置信息。
当服务器调用该方法时会将当前servlet的初始化配置存储在cnfig对象中
public void init(ServletConfig config) throws ServletException {
this.config=config; //缓存config对象
}
//用于供其它位置获取config对象时进行调用
private ServletConfig config;
public ServletConfig getServletConfig() {
return config;
}
//在init方法执行后,服务器调用service方法用于生成针对客户端的响应信息。服务器采用多
线程的方式运行service方法,一个客户端请求对应一个线程。服务器调用service方法时会传入2个参
数对象,req用于封装客户端的请求信息,resp用于封装服务器的响应信息。Servlet默认采用单实例
多线程的方式对客户端浏览器请求提供服务,service执行完成后不会自动销毁,而是常驻内存
public void service(ServletRequest req, ServletResponse resp) throws
ServletException, IOException {
}
//一般供获取当前servlet对象的说明信息
public String getServletInfo() {
return "当前servlet对象的说明信息";
}
//在servlet对象销毁之前执行,用于进行资源回收。一个servlet对象在整个生命周期运行且只
运行一次。servlet对象默认是常驻内存,只有在服务器关闭或者内存严重不足而当前Servlet对象被
GC机制选中时才会被销毁
public void destroy() {
}
} 2、在web.xml中针对servlet类进行配置,将servlet和一个或者多个地址建立对应关系
xml文件头用于说明当前xml文件的语法规则
将servlet类和一个名称建立对应关系
hello
com.yan.action.HelloServlet
将一个servlet名称和请求地址建立对应关系
hello
/hello.do
public abstract class HttpServlet extends GenericServlet,针对Servlet接口的5种
方法都提供了默认实现
//按照Servlet的运行规则,服务器会调用service方法对外提供服务。
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod(); //获取请求方法,http协议定义了7种请求,
例如get/post/put/delete,...
if (method.equals(METHOD_GET)) { //如果请求方法为GET,则调用doGet方法进
行处理
doGet(req, resp);
} else if (method.equals(METHOD_HEAD)) {
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
String errMsg =
lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
//针对不同的请求方法提供了对应的扩展点,运行子类进行覆盖定义
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String protocol = req.getProtocol(); //获取请求协议,例如http
String msg = lStrings.getString("http.method_get_not_supported");
//根据参数获取默认的报错信息
if (protocol.endsWith("1.1")) { 判断http协议的版本号,发送报错信息
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
} public void init(ServletConfig config) throws ServletException {}
//GenericServlet中的方法实现
public void init(ServletConfig config) throws ServletException {
this.config = config; //缓存服务器提供的config对象
this.init(); //提供扩展点
} 配置位于web.xml文件
hello3
com.yan.action.Hello3Servlet
初始化参数,可以配置多个
rows 配置的参数名称
3 对应配置参数名称的配置值
width
120
在servlet中获取配置参数 可以在GenericServlet提供的扩展点中获取配置参数 @Override
public void init() throws ServletException {
//获取对应名称的初始化参数值,如果没有配置则返回为null
//这个获取初始化参数的方法也可以在其它方法中进行调用,从而获取配置参数
String rows = this.getServletConfig().getInitParameter("rows");
System.out.println(rows);
//获取当前servlet的配置名称,对应web.xml中的hello3
System.out.println(
this.getServletConfig().getServletName()
):
//获取所有当前servlet的初始化配置参数名称的迭代器,类似Iterator
Enumeration initParameterNames =
this.getServletConfig().getInitParameterNames();
while(initParameterNames.hasMoreElements()){
String name=initParameterNames.nextElement(); //获取每个初始化配置
参数名称
String value=this.getServletConfig().getInitParameter(name);//根
据配置参数名称读取对应的参数配置值
System.out.println(name+"-->"+value);
}
//可以通过config对象获取当前应用的上下文
final ServletContext context =
this.getServletConfig().getServletContext();
} public class AddServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
// 操作请求头参数
final String host = request.getHeader("Host"); // 根据名称获取请求头中指
定的参数值
System.out.println(host);//localhost:8080
//另外根据发送数据的类型 request.getIntHeader("名称"):Int
request.getDateHeader():long
//获取所有的请求头参数名称的枚举对象
final Enumeration headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()){
String headerName=headerNames.nextElement();
String headerValue=request.getHeader(headerName);
System.out.println(headerName+"-->"+headerValue);
}
String name="Accept-Encoding"; //遍历一个名称对应的多个配置值的情形
final Enumeration enumeration = request.getHeaders("AcceptEncoding");//请求头中一个名称对应多个参数值
while(enumeration.hasMoreElements()){
String tmp=enumeration.nextElement();
System.out.println(name+"<-->"+tmp);
}
}
} public class AddServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
this.doPost(request,response); //将get请求转发给doPost进行处理
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse
resp) throws ServletException, IOException {
}
} @Override
protected void doPost(HttpServletRequest request, HttpServletResponse
resp) throws ServletException, IOException {
//根据参数名称获取对应的参数值
String username=request.getParameter("username");//在网络数据传输中只有
String类型,其它类型需要自行编码实现数据类型转换
//因为DateFormat不是线程安全的,所以DateFormat不能定义为属性
System.out.println(username);
//获取用于遍历所有请求参数名称的迭代器对象
final Enumeration parameterNames =
request.getParameterNames();
while(parameterNames.hasMoreElements()){
String parameterName=parameterNames.nextElement();
String parameterValue=request.getParameter(parameterName);
System.out.println(parameterName+"-->"+parameterValue);
}
//获取所有请求参数
final Map parameterMap =
request.getParameterMap();
for(String tmpName:parameterMap.keySet()){
String[] params=parameterMap.get(tmpName);
System.out.println(tmpName+"<===>"+ Arrays.toString(params
));
}
//针对checkbox获取数据的方法
final String[] hobbies = request.getParameterValues("hobby");
for(String tmp:hobbies)
System.out.println(tmp);
} 针对一个名称传递多个数据的情形 针对checkbox使用一个名称传递多个数据则必须使用getParameterValues获取数据,如果使用 getParameter则会有数据丢失 //针对checkbox获取数据的方法
final String[] hobbies = request.getParameterValues("hobby");
for(String tmp:hobbies)
System.out.println(tmp); 常见问题1:类型转换 数据传输都是String类型获取数据后需要进行类型转换,但是转换会有异常 实际处理中有2种不同的处理方案:方案1记录日志并继续向上抛出;方案2采用默认值
String sage=request.getParameter("age");
Integer age=null;
try {
age = Integer.parseInt(sage); //NumberFormatException运行时异常
} catch(Exception e){
//记录日志,如果需要程序中断,可以不做异常处理,因为NumberFormatException运行时异常
throw new ServletException(e);
age=18;//设定默认值。不是任何时候都可以采用自定义默认值的方式进行容错
} 常见问题2:一个名字对应多个数据的存储和显示 MySQL中并不建议使用enum枚举类型和set集合类型
多个选项的存储方案:
-- 一个专门用于存放各种常量的独立的表,字典表
create table tb_dict(
id bigint primary key auto_increment comment '代理主键',
type_ varchar(32) not null comment '用于标识数据的具体类型,例如sex表示用于性别
信息',
val_ varchar(20) not null comment '显示的数据'
-- key_ comment '存放具体提交数据'
)engine=innodb default charset utf8;
insert into tb_dict(type_,val_) values('sex','男');
insert into tb_dict(type_,val_) values('sex','女');
-- 注意具体存储对应数据时可以采用id编号值
具体入库数据
一种直接存储选项的显示值,优势在于方便显示 另外的存储方式存储的时字典表中对应的id值,优势在于方便修改,最大的缺陷在于额外查询
请求参数的中文问题
为了重现问题使用tomcat7插件
org.apache.tomcat.maven
tomcat7-maven-plugin
2.2
/pp 上下文路径名称,也就是访问应用的路径为/pp
9090 端口号的配置,localhost:9090/pp/
UTF-8 默认的编码字符集
因为在整个数据提交过程中会涉及多处编码字符集问题,1、提交所采用的编码字符集。 2、在互联网上传输数据默认编码字符集为ISO-8859-1。3、服务器接收数据后的编码处理
请求参数的中文乱码问题有3种解决方案
以tomcat为例的解决方案: conf/server.xml 需要掌握的配置参数1:修改请求的端口号,默认端口8080针对连接子 添加一个配置参数URIEncoding="GBK",这里的GBK来自于页面编码字符集
//根据参数名称获取对应的参数值 String username=request.getParameter("username");//在网络数据传输中只有 String类型,其它类型需要自行编码实现数据类型转换 //使用ISO8859-1进行解码转换,转换为原始的字节数组 byte[] arr=username.getBytes(StandardCharsets.ISO_8859_1); //再次使用UTF-8进行编码 username=new String(arr, Charset.forName("UTF-8")); System.out.println(username);理论上来说采用通用解决方案可以处理get和post的中文乱码问题,但是一般不采用这种方式,因为处理比较繁琐。具体开发实践中注意一些小细节即可,不用通用解决方案
//向request的attribute种存储数据,如果名称已经存在则后盖前,否则新增
request.setAttribute("name","具体数据Object");
//从request的attribute中获取数据
Object obj=request.getAttribute("name");
//按照key值删除指定的数据
request.removeAttribute("name");
//遍历attribute中的所有数据对应的key值
Enumeration attributeNames = request.getAttributeNames();
while(attributeNames.hasMoreElements()){
String attrName=attributeNames.nextElement();
Object attrValue=request.getAttribute(attrName);
System.out.println(attrName+"<-->"+attrValue)
} request.getRequestDispatcher("https://www.baidu.com").forward(request,resp onse); 执行会有报错 HTTP Status 404 - /pp/https:/www.baidu.com ,这是在请求转发 时会在地址上自动附加当前应用的路径 http://localhost:9090/pp/
request.getRequestDispatcher("add2.do?id=100").forward(request,response); 请求当前页面的参数仍旧存在。如果参数名称一致,则时附加,也就是名称相同的多个参数 如果昂前页面的请求方法为post,请求转发请求方法仍旧为post
原因是共享request
获取客户端的地址
//获取远程客户端的IP地址 System.out.println(request.getRemoteAddr()); stem.out.println(request.getRemoteHost()); //获取远程客户端的连接端口号 System.out.println(request.getRemotePort()); //获取服务器的IP地址 System.out.println(request.getLocalAddr()); //获取本地机的主机名称 System.out.println(request.getLocalName()); //获取本地机的连接端口号 System.out.println(request.getLocalPort()); //获取服务器的信息 System.out.println(request.getServerName()); System.out.println(request.getServerPort());
String ss="192.168.123.4";
long res=0;
String[] arr=ss.split("[.]");
for(int i=0;i 获取请求地址相关信息 //String统一资源标识符 /pp/add.do System.out.println(request.getRequestURI()); //StringBuffer统一资源定位器 http://localhost:9090/pp/add.do System.out.println(request.getRequestURL()); //获取上下文路径 /pp System.out.println(request.getContextPath()); //获取请求参数 对应get请求时?号后面的内容,例如id=999。如果没有请求参数或者post参数则为 null System.out.println(request.getQueryString());
流式处理
//获取http请求方法,例如GET/POST/DELETE等
String method=request.getMethod();