文章目录
1-Servlet 配置要点
- 全路径匹配
> 以"/"开始。如:/a、/aa/bb
> localhost:8080/项目名称/aa/bb - 路径匹配,前半段匹配
> 以"/“开始 ,但是以” * "结束 。如:/a/* 、/*
> * 其实是一个通配符,匹配任意文字
> localhost:8080/项目名称/aa/bb - 以扩展名匹配
> 写法:以" * "开始 。如:.扩展名、.aa、*.bb
ServletContext 配置全局参数,与Java类似,定义在外面,具体如下:
<!-- 定义全局参数 -->
<context-param>
<param-name>favorite</param-name>
<param-value>type and thinking</param-value>
</context-param>
2-ServletContext 获取资源文件(重点要考)
ServletContex有什么作用?
- 获取全局配置参数
- 获取web工程中的资源
- 存取数据,servlet间共享数据域对象
ServletContext 何时创建,何时销毁?
- 服务器启动的时候,会为托管的每一个web应用程序,创建一个ServletContext对象
- 从服务器移除托管,或者是关闭服务器
ServletContext的作用范围:只要在同一项目中,都可以取。
问:A项目存,为什么在B项目取不到的? 答:ServletContext对象不同
这里就不多BB,直接上我的之前写的一篇博客:Servlet读取文件方式总结
3-ServletContext 获取登录成功总数
- 要提供信息,肯定要可视化界面,所以写一个html,要form表单提供信息
- 要获取信息,写一个Servlet,并且去web.xml中配置,利用req对象的getParameter方法获取信息
- 校验填写信息是否正确,并打印结果,具体代码如下:
index.html中:
LoginServlet的doGet中:<body> <h2>请登录!</h2> <form action="login" method="get"> 账号:<input type="text" name="username"> 密码:<input type="text" name="password"> <input type="submit" value="登录"> </form> </body>
String username = req.getParameter("username"); String password = req.getParameter("password"); if(username.equals("hpf")&&password.equals("123456")){ System.out.println("login success!"); resp.getWriter().write("login success!"); }else{ System.out.println("login faild!"); resp.getWriter().write("login faild!"); }
- 要实现登录成功的跳转,首先必须还得有一个login_success.html,里面提供一个用于获取次数
- 要获取次数,必须还要有一个CountServlet。并且,利用ServletContext来获取次数,并打印于页面
- 个人书写代码总结与注意点:
1.html与Servlet的关联,即form中的action所填写的内容必须是web.xml中配置的url-pattern
2.每写一个Servlet(除了新建的时候选择Servlet),否则,一定要手动在web.xml中配置
3.doGet与doPost中的请求和响应对象都要利用好,这里使用到了信息的获取及页面的跳转
4.ServletContext可以设置属性,并且读取属性,这是获取次数的关键所在
5.Servlet路径和html路径实际上在运行时是在同一路径下的,都是在工程目录下,同级
以下为示例的完整代码(完整版):
index.html中:
<body>
<h2>请登录!</h2>
<form action="login" method="get">
账号:<input type="text" name="username">
密码:<input type="text" name="password">
<input type="submit" value="登录">
</form>
</body>
LoginServlet的doGet中:
ServletContext sc = getServletContext();
String username = req.getParameter("username");
String password = req.getParameter("password");
Object count = sc.getAttribute("count");
if(count==null){
count = 1;
sc.setAttribute("count", (int)count);
}else{
sc.setAttribute("count",((int)count+1));
}
if(username.equals("hpf")&&password.equals("123456")){
System.out.println("login success!");
//设置状态码
resp.setStatus(302);
//定位跳转的位置是哪个页面
resp.setHeader("Location", "loginSuccess.html");
}else{
System.out.println("login faild!");
resp.getWriter().write("login faild!");
}
loginSuccess.html中:
<body>
<h1>congratulation!login success!</h1>
<a href="count">点击获取登录成功的次数</a>
</body>
CountServlet的doGet中:
ServletContext sc = getServletContext();
int count = (int)sc.getAttribute("count");
resp.getWriter().write("count:"+count);
4-HttpServletRequest与中文乱码问题
问:HttpServletRequest到底有什么用? 答:这个对象封装了客户端提交过来的一切数据。
-
可以获取客户端请求头信息
//得到一个枚举集合 Enumeration<String> headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String name = (String) headerNames.nextElement(); String value = request.getHeader(name); System.out.println(name+"="+value); }
-
获取客户端提交过来的数据
String name = request.getParameter("name"); String address = request.getParameter("address"); System.out.println("name="+name); System.out.println("address="+address); ------------------------------------------------- //name=zhangsan&name=lisi&name=wangwu 一个key可以对应多个值。 Map<String, String[]> map = request.getParameterMap(); Set<String> keySet = map.keySet(); Iterator<String> iterator = keySet.iterator(); while (iterator.hasNext()) { String key = (String) iterator.next(); System.out.println("key="+key + "--的值总数有:"+map.get(key).length); String value = map.get(key)[0]; String value1 = map.get(key)[1]; String value2 = map.get(key)[2]; System.out.println(key+" ======= "+ value + "=" + value1 + "="+ value2); } //一般情况下,传过来的数据不可能是name=hpf&name=hillain,所以上面的value数组一般不写
-
获取中文数据
客户端提交数据给服务器端,若数据中带有中文并出现乱码情况,则可以参照以下方法解决
1、如果是GET方式://使用代码转码 String username = request.getParameter("username"); String password = request.getParameter("password"); System.out.println("userName="+username+"==password="+password); //get请求过来的数据,在url地址栏上就已经经过编码了,所以我们取到的就是乱码 //tomcat收到了这批数据,getParameter 默认使用ISO-8859-1去解码 //先让文字回到ISO-8859-1对应的字节数组 , 然后再按utf-8组拼字符串 username = new String(username.getBytes("ISO-8859-1") , "UTF-8"); System.out.println("userName="+username+"==password="+password);
//可以在tomcat里面做设置处理,conf/server.xml加上URIEncoding="utf-8" //直接在tomcat里面做配置,以后get请求过来的数据永远都是用UTF-8编码 <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>
2、如果是POST方式
request.setCharacterEncoding("UTF-8"); //这行设置一定要写在getParameter之前 请求体里面的文字编码get方式,用这行,有用吗? ---> 没用
关于使用get导致的乱码为什么需要用ISO-8859-1来解,看下图就知道了:
5-HttpServletResponse与中文乱码问题
问:HttpServletResponse到底有什么用? 答:这个对象负责返回数据给客户端。
//以字符流的方式写数据
//response.getWriter().write("<b>hello response...</b>");
//以字节流的方式写数据
response.getOutputStream().write("hello response2222...".getBytes());
响应的数据中有中文,那么有可能出现中文乱码
下面详细说明了2两种出现中文乱码的情况以及如何解决:
-
以字符流输出
response.getWriter() //1. 指定输出到客户端的时候,这些文字使用UTF-8编码 response.setCharacterEncoding("UTF-8"); //2. 直接规定浏览器看这份数据的时候,使用什么编码来看 response.setHeader("Content-Type", "text/html; charset=UTF-8"); response.getWriter().write("这是个测试...");
-
以字节流输出
response.getOutputStream() //1. 指定浏览器看这份数据使用的码表 response.setHeader("Content-Type", "text/html;charset=UTF-8"); //2. 指定输出的中文用的码表 response.getOutputStream().write("这是个测试...".getBytes("UTF-8"));
-
不管是字节流还是字符流,直接使用一行代码就可以了
response.setContentType("text/html;charset=UTF-8");
6-HttpServletResponse实现下载文件
其实实现很简单,最简单的莫过于直接利用Tomcat提供下载。即你写一个html,把文件放上去,运行Web,然后鼠标点击即可下载,但是这里的下载是会直接打开的,也就是说如果不是文本,而是压缩包之类的话,是会直接显示乱码的,所以这种方式并不可取。
那就先说一下为什么我们什么都不用做就可以实现下载,这是因为Tomcat里有一个默认的Servlet,也就是DefaultServlet,这个Servlet专门用于处理放在Tomcat服务器上面的静态资源,也就是Html、Css这类的东西。
下面就来手动实现一下利用Response来下载文件:
- 先写html,将href改为"Servlet名?filename=文件名.格式"
- 写一个Servlet,首先获取数据,然后获取文件路径,设置以对话框的方式下载文件,最后使用流保存
- 代码如下:
download.html:
HttpServletResponse:<body> <h3>文件下载</h3> <a href="test?filename=lqtzs.png">lqtzs.png</a> </body>
//1.获取下载的文件名字aa.jpg -- inputStream String fileName = req.getParameter("filename"); //2.获取这个文件在tomcat里面的绝对路径地址 String path = getServletContext().getRealPath(fileName); //让浏览器收到这份资源的时候,以下载的方式提醒用户,而不是直接显示 resp.setHeader("Content-Disposition", "attachment; filename="+fileName); //3.转换成输入法(若没有3,也有对话框,不过没法保存) InputStream is = new FileInputStream(path); OutputStream os = resp.getOutputStream(); int len = 0; byte[] buffer = new byte[1024]; while((len = is.read(buffer))!=-1){ os.write(buffer,0,len); } os.close(); is.close();
7-Servlet综合训练
综合训练 - 实现注册,保存数据,跳转到登录,并在线下载
心得与总结:
- 首先,如果新建了一个Web工程的话,如果要将这个工程删除,那么一定要先去工作环境中把这个删了
- getContextPath.getRealPath(“文件名”)也适用于将要存储的文件,原先并不存在
- Writer的写法以及OutputStream的写法有点生疏了,resp的跳转以及刷新等功能还要继续加强学习
- resp.setContentType(“text/html;charset=UTF-8”);代码解决中文乱码很重要
- 因为我们自己定义的OutputStream要写文件路径,相当于把路径写死了,所以我们在下载的代码中应写resp.getOutputStream,其实很好理解,就是用服务器响应的输出流,将文件输出
- 具体Version1完整代码如下:
regist.html:
SaveServlet:<body> <h3>请注册:</h3> <form action="save" method="get"> 账号:<input type="text" name="username"><br><br> 密码:<input type="password" name="password"><br><br> 昵称:<input type="text" name="nickname"><br><br> <input type="submit" value="注册"> </form> </body>
login.html:ServletContext sc = getServletContext(); //String realPath = sc.getContextPath(); //System.out.println(realPath); //测试路径 //获得Map集合 Map<String, String[]> pm = req.getParameterMap(); Set<String> ks = pm.keySet(); Iterator<String> iterator = ks.iterator(); Writer os = new FileWriter(sc.getRealPath("user.properties")); while(iterator.hasNext()){ String key = iterator.next(); String value = pm.get(key)[0]; String parameter = new String(key+"="+value); System.out.println(); System.out.printf(parameter); os.write(parameter); os.append("\n"); } os.close(); //设置跳转 resp.setStatus(302); resp.setHeader("Location", "login.html");
LoginServlet:<body> <h3>请登录:</h3> <form action="login"> 账号:<input type="text" name="username"> 密码:<input type="password" name="password"> <input type="submit" value="登录"> </form> </body>
download.html:String username_req = req.getParameter("username"); String password_req = req.getParameter("password"); Properties ps = new Properties(); ServletContext sc = getServletContext(); InputStream is = sc.getResourceAsStream("user.properties"); ps.load(is); String username_ps = ps.getProperty("username"); String password_ps = ps.getProperty("password"); resp.setContentType("text/html;charset=UTF-8"); if(username_req.equals(username_ps)&&password_req.equals(password_ps)){ resp.setStatus(302); resp.setHeader("Location", "download.html"); }else{ resp.getWriter().write("账号密码输入错误!"); resp.setHeader("refresh", "3;login.html"); }
DownloadServlet:<body> <h3>请选择合适文件下载</h3> <a href="download?filename=lqtzs.png">lqtzs.png</a> </body>
//1.获取下载的文件名字aa.jpg -- inputStream String fileName1 = req.getParameter("filename"); System.out.println(fileName1); //2.获取文件名的时候,以防中文乱码也要转码 fileName1 = new String(fileName1.getBytes("ISO-8859-1"),"UTF-8"); System.out.println(fileName1); //3.获取这个文件在tomcat里面的绝对路径地址 String path = getServletContext().getRealPath(fileName1); /*4.如果文件的名字带有中文,那么要对这个文件名进行编码处理 如果是IE或者Chrome,使用URLEncoding编码 如果是Firefox,使用Base64编码*/ String ua = req.getHeader("User-Agent"); if(ua.contains("Firefox")){ fileName1 = DownloadUtil.base64EncodeFileName(fileName1); }else{ fileName1 = URLEncoder.encode(fileName1, "UTF-8"); } //5.让浏览器收到这份资源的时候,以下载的方式提醒用户,而不是直接显示 resp.setHeader("Content-Disposition", "attachment; filename="+fileName1); InputStream is = new FileInputStream(path); OutputStream os = resp.getOutputStream(); byte[] bytes = new byte[1024]; int len = -1; while((len = is.read(bytes))!=-1){ os.write(bytes, 0, len);; } os.close(); is.close();
自我总结
我认为这一部分的重点就是中文乱码的处理以及Html和Servlet之间连接的一种思路了,因为response和request,其实用着用着就会了。而难点可能就是利用输入输出流的操作,因为我之前就犯了个错误,在DownloadServlet书写的时候,Outputstream就没有用resp.getOutputStream,而是随手new了一个,哈哈哈,结果可想而知。
这是一篇笔记博客,如果能帮到人的话那更好了哈哈哈。Last but not least,学习与坐禅相似,须有一颗恒心。