Servlet的编码
之前我们对前端传过来的数据进行插入用的是英文,我们现在用中文来试一下
数据库乱码了,所以我们要再dopost获取参数之前就要设置编码
req.setCharacterEncoding("UTF-8");
String fname = req.getParameter("fname");
String priceStr = req.getParameter("price");
Integer price = Integer.parseInt(priceStr);
String fcountStr = req.getParameter("fcount");
Integer fcount = Integer.parseInt(fcountStr);
String remark = req.getParameter("remark");
System.out.println(fname);
System.out.println(price);
System.out.println(fcount);
System.out.println(remark);
现在:
数据库插入的就是中文了
补充:
Servlet继承关系
相关方法:
servlet里的service是自动调用的,那么这个方法干了什么呢?我们进入源码查看
servlet里方法是抽象的,我们向下一层看
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
GenericServlet里的service方法还是抽象的,我们向下一层看
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
}
httpservlet里的service终于不是抽象的了
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
我们发现这里面是获取到了请求方式,再执行对应操作,我们看看如果是post,会干什么
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_post_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
那么,如果我们在我们的代码里重写dopost,但是请求方式是get会发生什么事情?
已经知道客户端默认向服务器发请求是get,我们只写dopost
public class ServletRelation extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
web.xml
<servlet>
<servlet-name>ServletRelation</servlet-name>
<servlet-class>com.LALALA.servlets.ServletRelation</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletRelation</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
tomcat:
结果:
为什么会是405????
我们现在没有doget,会调用父类中的doget,也就是httpservlet里的doget
if (lastModified == -1L) { this.doGet(req, resp);
我们看看这个doget干了什么
这边就会返回我们的错误编码和信息
Servlet的生命周期
我们自己重写看一下流程
public class ServletLife extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("init..............");
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("service...........");
}
@Override
public void destroy() {
System.out.println("destroy............");
}
}
此时我们访问demo02,我们发现
此时servlet只会初始化一次,无论再怎么刷新页面,都会进行service
在关闭服务器的时候会进行销毁
好处:提高系统的启动速度
坏处:第一次请求时,耗时会非常长
我们可以通过设置servlet的初始化时机
数字越小,启动的越早
此时在启动的时候已经完成了初始化
什么是单例的?
此时我们的项目结构无论是relation还是life都是初始化一个servlet来进行实现我们的操作,这就是单例的
什么是线程不安全的?
和之前JDBC的事务问题类似
HTTP协议
会话Session
之前我们说HTTP协议是无状态的,什么意思?
下面我们来代码验证一下
public class ServletSession01 extends HttpServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpSession session = request.getSession();
System.out.println("Session ID:::"+session.getId());
}
}
<servlet>
<servlet-name>ServletSession01</servlet-name>
<servlet-class>com.LALALA.servlets.ServletSession01</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletSession01</servlet-name>
<url-pattern>/demo03</url-pattern>
<servlet-mapping>
调用demo03页面后
我们发现前端会收到一个响应头,里面的setsession和我们控制台收到的一样,这是第一次,服务器给客户端创建了一个sessionID
如果我们这个时候再刷新页面,sessionID还是不会改变,并且服务器不会给这个会话创建新的ID
此时服务器发送请求会带着自己的会话ID在请求头里给服务器
Session保存作用域
我们可以向session里保存一些数据,为了使我们保存的数据不冲突,我们需要session保存作用域,也就是会话1保存的内容不能被会话2访问
public class ServletSession02 extends HttpServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
request.getSession().setAttribute("uname","LALALA");
}
}
public class ServletSession03 extends HttpServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
Object uname = request.getSession().getAttribute("uname");
System.out.println(uname);
}
}
<servlet>
<servlet-name>ServletSession02</servlet-name>
<servlet-class>com.LALALA.servlets.ServletSession02</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletSession02</servlet-name>
<url-pattern>/demo04</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ServletSession03</servlet-name>
<servlet-class>com.LALALA.servlets.ServletSession03</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletSession03</servlet-name>
<url-pattern>/demo05</url-pattern>
</servlet-mapping>
演示:
先访问demo04再访问demo05
可以正常输出我们设置的值
那么如果先访问04,再换个浏览器访问05会如何?
此时换浏览器访问05不能获取
所以这个保存域中的东西是靠sessionid来区分保存的
服务器转发和客户端重定向
服务器转发:
客户端重定向: