1.@WebServlet注解的作用
在Servlet 3.0中,使用@WebServlet注解可实现servlet和url的映射,它告知容器哪些Servlet会提供服务以及额外信息,其作用相当于之前在web.xml中设置的servlet配置。
以下两种方法二选一:
a.一种使用注解
1 @WebServlet{helloUser} 2 public class helloUser extends HttpServlet{ 3 }
只要在Servlet上设置@WebServlet标注,容器就会自动读取当中的信息。上面的@WebServlet告诉容器,如果请求的URL是“/helloUser”,则由helloUser的实例提供服务。
可以使用@WebServlet提供更多信息。
1 @WebServlet( 2 name="Hello", 3 urlPatterns={"/hello.view"}, 4 loadOnStartup=1 5 ) 6 public class HelloServlet extends HttpServlet {
上面的@WebServlet告知容器,HelloServlet这个Servlet的名称是Hello,这是由name属性指定的,而如果客户端请求的URL是/hello.view,则由具Hello名称的Servlet来处理,这是由urlPatterns属性来指定的。在Java EE相关应用程序中使用标注时,可以记得的是,没有设置的属性通常会有默认值。例如,若没有设置@WebServlet的name属性,默认值会是Servlet的类完整名称。
当应用程序启动后,事实上并没有创建所有的Servlet实例。容器会在首次请求需要某个Servlet服务时,才将对应的Servlet类实例化、进行初始化操作,然后再处理请求。这意味着第一次请求该Servlet的客户端,必须等待Servlet类实例化、进行初始动作所必须花费的时间,才真正得到请求的处理。
如果希望应用程序启动时,就先将Servlet类载入、实例化并做好初始化动作,则可以使用loadOnStartup设置。设置大于0的值(默认值为-1),表示启动应用程序后就要初始化Servlet(而不是实例化几个Servlet)。数字代表了Servlet的初始顺序,容器必须保证有较小数字的Servlet先初始化,在使用标注的情况下,如果有多个Servlet在设置loadOnStartup时使用了相同的数字,则容器实现厂商可以自行决定要如何载入哪个Servlet。
b.使用web.xml配置方式
1 <servlet> 2 <servlet-name>helloUser</servlet-name> 3 <servlet-class>com.servlet.HelloUser</servlet-class> 4 </servlet> 5 <servlet-mapping> 6 <servlet-name>helloUser</servlet-name> 7 <url-pattern>/helloUser</url-pattern> 8 </servlet-mapping>
2.多个请求访问同一个servlet
在我们刚开始编写java web程序时,可能会一个jsp页面功能对应一个服务器的servlet。例如对我们的客户表(Customer)实行增删改查时,每个操作对一个servlet。这样的话,不仅使得代码量很大,而且会使得代码不好管理。那我们想到的是,怎么实现JSP页面的多个请求对应一个servlet呢?通过一个servlet完成增删改查等多个功能呢?
例如我的jsp页面中查询数据库中的表customer时,展现的如下图所示
我们需要实现的是在输入框中输入要查找的名字或者地址或者电话时,可以实现模糊查询,点击submit时,可以在当前页面下面显示查询的数据结果,例如输入数据库中有的用户名rose
再点击submit,页面呈现
当点击upadate和Delete,可是实现对用户的信息修改和删除功能。在我们刚开始的学习中,会将这些功能都分别对应一个servlet,现在实现的就是这些功能都对应一个servlet。
第一:我们可以在jsp页面中对from中的action统一格式为,都以.do结尾。
1 <form action="query.do" method="post"> 2 <td><a href="addCustomer.jsp">Add a new customer</a></td> 3 <td><a href="edit.do?id=<%=customer.getId() %>">Update</a></td> 4 <td><a href="delete.do?id=<%=customer.getId() %>">Delete</a></td> 5 </form>
那么在我们的一个名为CustomerServlet的web.xml配置文件中可以改写为
1 <servlet> 2 <servlet-name>CustomerServlet</servlet-name> 3 <servlet-class>com.servlet.CustomerServlet</servlet-class> 4 </servlet> 5 <servlet-mapping> 6 <servlet-name>CustomerServlet</servlet-name> 7 <url-pattern>*.do</url-pattern> 8 </servlet-mapping>
那么只要页面中以.do结尾的action在提交后,都会去寻找CustomerServlet。那么我们在CustomerServlet中怎么辨别每一个不同的action呢?我们的做法如下:我们在CustomerServlet中的doGet方法中实现
1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 2 //获取servletpath 3 String servletPath = request.getServletPath(); 4 //去除路径后缀名中的.do 5 String methodName = servletPath.substring(1); 6 methodName = methodName.substring(0, methodName.length()-3); 7 8 try { 9 //利用反射获取methodName 对应的方法 10 Method method = getClass().getDeclaredMethod(methodName, 11 HttpServletRequest.class, 12 HttpServletResponse.class); 13 //利用反射调用相应的方法 14 method.invoke(this, request, response); 15 } catch (Exception e) { 17 response.sendRedirect("error.jsp"); 18 } 19 }
这样实现可以根据页面的不同请求,截掉.do,得到不同请求名。但注意的是必须页面中的请求名和seevlet中各实现功能的方法名相同。如页面中是delete.do,那么我们的servlet中的方法名就应该写成delete,这样才能该请求获取相应的功能。
3.继承httpservlet实现service/doget/dopost之间的关系
如下图,service方法中判断请求(request)的方式(getMethod()),若返回“GET”则调用doGet方法,返回"POST"则调用doPost方法,若为其他put/delete等方法,则调用相应的方法。即service负责根据请求调度其它方法。
浏览器访问Servlet过程示意图
Servlet主要作用就是处理客户端请求和响应。浏览器每一次请求Servlet,服务器Tomcat在调用Service()方法之前,都会创建两个对象,分别是HttpServletRequest对象和HttpServletResponse对象。HttpServletResponse的作用:封装HTTP响应消息。
HttpServletRequest对象:
a.作用:
封装HTTP请求消息
获取请求头、请求行、请求消息体
b.获取请求行的一些方法
1 String getMethod():获取HTTP请求消息的请求方式。 2 String getRequestURI():获取URL的主机和端口号之后,参数部分之前的部分。 3 String getQueryString():获取资源路径以后的所有内容。 4 String getProtacol():获取请求行的协议名和版本。 5 String getContextPath():获取web应用程序的路径。 6 String getServletPath():获取Servlet映射的路径。 7 String getRemoteAddr():获取客户端的IP地址。 8 String getRemoteHost():获取完整主机名。 9 String getLocalName():获取web服务器上接收当前网络连接IP对应的主机名。 10 String getLocalAddr():获取web服务器上接收当前网络连接IP地址。 11 String getServletName():获取当前请求 所指向的主机名。 12 int getServletPort():获取当前请求所连接的服务器端口号。 13 String getScheme():获取请求协议名。 14 StringBuffere getRequestURL():获取客户端发出请求的完整URL.
c.输出结果 :
d.HttpServletRequest获取请求消息头的一些方法
1 String getHeader(String name):获取指定头字段值 2 Emumeration getHeaders(String name):获取Emumeration集合 3 Emumeration getHeaderNames():获取一个包含所有请求头字段的Emumeration 4 int getIntHeader(String name):获取指定名称的头字段。 5 long getDateHeader(String name):获取指定头字段的值。 6 String getContentType():获取Content-type头字段值。 7 int getContentLength():获取Content-Type头字段的值。 8 String getCharacterEncoding():获取编码。
HttpServletResponse对象
a.作用 :
封装HTTP响应消息(响应状态行、响应消息头、响应消息体)
b.发送状态码的一些方法
setStatus(int status):设置HTTP消息响应的状态码,并生成消息的相应行。
sendError(int sc):发送表示错误消息的状态码。
c.发送响应消息头的一些方法
1 void addHeader(String name,String value) 2 void setHeader(String name,String value):设置HTTP协议响应头字段。 3 void addIntHeader(String name,int value): 4 void setIntHeader(String name,int value):设置包含整数值得消息头 5 void setContentType(String type):设置Servlet输出内容的MIME类型 6 void setContentLength(int len):设置响应消息体的内容大小,单位为字节。 7 void setLocale(locale loc):设置响应消息体的本地化消息。 8 void setCharacterEncoding(String charset):设置输出内容使用的编码。
d.发送响应消息的一些方法
Servlet中的数据要呈现到浏览器界面,需要通过IO流来实现
getOutputStream():直接输出字节数组中的二进制数据。(ServletOutputStream)
getWriter():输出的内容全部为字符文本的网页文档。(PrintWriter)
4.ServletContext.getRealPath()
ServletContext.getRealPath() 是从当前servlet 在tomcat 中的存放文件夹开始计算起的
比如,有个servlet 叫 UploadServlet,它部署在tomcat 下面以后的绝对路径如下:
"C:\Program Files\apache-tomcat-8.0.3\webapps\UploadServlet"
那么,
ServletContext.getRealPath("/") 返回 "C:\Program Files\apache-tomcat-8.0.3\webapps\UploadServlet"
ServletContext.getRealPath("/attachment") 返回 "C:\Program Files\apache-tomcat-8.0.3\webapps\UploadServlet\attachment"
ServletContext.getRealPath("attachment") 会导致NullPointerException
结论就是:
在使用ServletContext.getRealPath() 时,传入的参数是从 当前servlet 部署在tomcat中的文件夹算起的相对路径,要以"/" 开头,否则会找不到路径,导致NullPointerException
测试如下:
1 System.out.println("request.getServletContext().getRealPath(\"/\")+\"WEB-INF\":"+request.getServletContext().getRealPath("/")+"WEB-INF"); 2 System.out.println("request.getServletContext().getRealPath(\"/\")+\"WEB-INF\\\\web.xml\"):"+request.getServletContext().getRealPath("/")+"WEB-INF\\web.xml"); 3 System.out.println("request.getServletContext().getRealPath(\"/index.html\"):"+request.getServletContext().getRealPath("/index.html"));
4.System.out.println("request.getServletContext().getRealPath(\"index.html\"):"+request.getServletContext().getRealPath("index.html"));
5. System.out.println("request.getServletContext().getRealPath(\"/\"):"+request.getServletContext().getRealPath("/"));
结果如下:
1 request.getServletContext().getRealPath("/")+"WEB-INF":G:\gitrepository\Spring_MVC_071-master\target\SpringMVC71-0.0.1-SNAPSHOT\WEB-INF 2 request.getServletContext().getRealPath("/")+"WEB-INF\\web.xml"):G:\gitrepository\Spring_MVC_071-master\target\SpringMVC71-0.0.1-SNAPSHOT\WEB-INF\web.xml 3 request.getServletContext().getRealPath("/index.html"):G:\gitrepository\Spring_MVC_071-master\target\SpringMVC71-0.0.1-SNAPSHOT\index.html
4 request.getServletContext().getRealPath("index.html"):null
5 request.getServletContext().getRealPath("/"):G:\gitrepository\Spring_MVC_071-master\target\SpringMVC71-0.0.1-SNAPSHOT\
5.解决中文输出乱码问题
方法一:
response.setContentType("text/html,charser=utf-8");
方法二:
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Type","text/html;charset=utf-8")
参考网址
https://my.oschina.net/zjllovecode/blog/961994
https://blog.csdn.net/congmingpig_htt/article/details/50492339
https://blog.csdn.net/sinat_32560085/article/details/70144760
https://blog.csdn.net/weixin_36279318/article/details/77990402