掌握filter的编写
能够使用filter实现权限过滤和统一字符编码

Filter开发分成以下三个步骤
1.定义类,实现Filter接口,并重写其所有方法
public class FilterDemo implements Filter {
public void init(FilterConfig filterConfig){...}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain){...}
public void destroy(){...}
}
2.配置Filter拦截资源的路径:在类上定义@WebFilter注解,其注解的value属性值跟@WebServlet的匹配规则基本一致
拦截所有资源:@WebFilter("/*")
@WebFilter(/*)
public class FilterDemo implements Filter {....}
3.在doFilter(...)方法中编写拦截资源的逻辑代码
public void doFilter(....){
System.out.println("filter 被执行了...");
// 放行
filterChain.doFilter(servletRequest, servletResponse);
}
其中放行的意思是,对当前客户端访问服务端的资源,不设置拦截;否则客户端无法访问

上图是过滤器的执行流程,不难发现,其特点为
总结
Filter的执行流程
Filter 会对哪些请求的资源进行拦截,使用@WebFilter注解进行配置。如:@WebFilter("拦截路径")/index.jsp:只有访问index.jsp文件的时候才会被拦截/user/*:访问/user下的所有资源,都会被拦截*.jsp:访问后缀名为jsp的资源,都会被拦截/*:访问所有资源,都会被拦截servlet的请求资源路径配置一样,但是表示的含义不同servlet的补充
- tomcat或者其他的servlet容器,都提供了两个servlet:DefaultServlet和JspServlet
- JspServlet的处理路径为"*.jsp":用来处理所有jsp请求(jsp本质上也是一个servlet),第一次请求这个jsp文件的时候,JspServlet就会将这个jsp文件装成java文件,然后编译成class文件,class文件才能执行.生成了响应
- DefaultServlet的处理路径为"/",用来处理其他servlet都处理不了的请求,找对应的静态资源,若找到就把静态资源(流)读进来,生成响应代码. 若也没有找到这个资源,就会通过tomcat或者其他的servlet容器生成404状态码

Filter1 的放行前逻辑代码Filter1 的放行代码Filter2 的放行前逻辑代码Filter2 的放行代码Filter2 的放行后逻辑代码Filter1 的放行后逻辑代码PS:
- 过滤器的执行流程和类的名称有一定的关系
- 当使用注解方式配置Filter的拦截路径的时候,其会根据类名的ascii码值的大小来分出执行顺序
- 如Filter2和Filter3,就会先执行Filter2过滤器
- 如BFilterDemo和AFilterDemo,就会先执行AFilterDemo过滤器
Filter代码
@WebFilter("/*")
public class LoginFilter implements Filter throws ServletException, IOException{
public void init(FilterConfig config) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
//1. 判断session中是否有user(PS:当用户成功登录后,会将用户的部分信息保存至Session)
HttpSession session = req.getSession();
Object user = session.getAttribute("user");
//2. 判断user是否为null
if(user != null){
// 登录过了
//放行
chain.doFilter(request, response);
}else {
// 没有登陆,存储提示信息,跳转到登录页面
req.setAttribute("login_msg","您尚未登陆!");
req.getRequestDispatcher("/login.jsp").forward(req,response);
}
}
public void destroy() {
}
}
不难看出,因为过滤器拦截了所有的资源,甚至连静态资源都不能访问,同时主页页面也会被拦截;显然,这种设计并不合理
完整过滤器代码
@WebFilter("/*")
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
//判断访问资源路径是否和登录注册相关
//1,在数组中存储登陆和注册相关的资源路径
String[] urls = {"/login.jsp","/imgs/","/css/","/loginServlet","/register.jsp","/registerServlet","/checkCodeServlet"};
//2,获取当前访问的资源路径
String url = req.getRequestURL().toString();
//3,遍历数组,获取到每一个需要放行的资源路径
for (String u : urls) {
//4,判断当前访问的资源路径字符串是否包含要放行的的资源路径字符串
/*
比如当前访问的资源路径是 /brand-demo/login.jsp
而字符串 /brand-demo/login.jsp 包含了 字符串 /login.jsp ,所以这个字符串就需要放行
*/
if(url.contains(u)){
//找到了,放行
chain.doFilter(request, response);
//break;
return;
}
}
//1. 判断session中是否有user
HttpSession session = req.getSession();
Object user = session.getAttribute("user");
//2. 判断user是否为null
if(user != null){
// 登录过了
//放行
chain.doFilter(request, response);
}else {
// 没有登陆,存储提示信息,跳转到登录页面
req.setAttribute("login_msg","您尚未登陆!");
req.getRequestDispatcher("/login.jsp").forward(req,response);
}
}
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
}
@WebFilter("/*")
public class CharacterEncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 向下转型
HttpServletRequest request = (HttpServletRequest) servletRequest;
// 判断请求是否为POST请求
String method = request.getMethod();
if ("post".equalsIgnoreCase(method)) {
// 如果是POST请求则设置编码
request.setCharacterEncoding("utf-8");
}
// 不管是不是,最后都要放行;不用分别在if和else中都写放行
filterChain.doFilter(request, servletResponse);
}
@Override
public void destroy() {
// Filter.super.destroy();
}
}
过滤器默认只过滤从浏览器直接发过来的请求。
解决方法--修改默认拦截方式
@WebFilter(value = "/c/*",dispatcherTypes = {DispatcherType.FORWARD,DispatcherType.REQUEST})
DispatcherTpye属性设置了之后,其过滤器的默认值就会失效
同时DispatcherType属性可以设置多个值
application,session,request 三个对象创建、销毁或者往其中添加修改删除属性时自动执行代码的功能组件。application概念
application 是 ServletContext 类型的对象ServletContext代表整个Web应用,在服务器启动的时候,Tomcat会自动创建该对象。在服务器关闭的时候会自动销毁该对象| 监听器 | 监听器名称 | 作用 |
|---|---|---|
| ServletContext监听 | ServletContextListener | 用于对ServletContext对象进行监听(创建、销毁) |
| ServletContextAttributeListener | 对ServletContext对象中属性进行监听(增删改属性) | |
| Session监听 | HttpSessionListener | 对Session对象的整体状态的监听(创建、销毁) |
| HttpSessionAttributeListener | 对Session对象中的属性进行监听(增删改属性) | |
| HttpSessionBindingListener | 对Session对象的绑定和解除进行监听 | |
| HttpSessionActivationListener | 对Session数据的钝化和活化进行监听 | |
| Request监听 | ServletRequestListener | 对Request对象进行监听(创建、销毁) |
| ServletRequestAttributeListener | 对Request对象中的属性进行监听(增删改属性) |
这八类监听器之中,ServletContextListener在后期学习中最常使用
- 其接口中主要有以下两种方法
void contextInitialized(ServletContextEvent sce):ServletContext对象被创建了会自动执行的方法void contextDestroyed(ServletContextEvent sce):ServletContext对象被销毁时会自动执行的方法
代码演示
@WebListener
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
//加载资源
System.out.println("ContextLoaderListener...");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
//释放资源
}
}
JavaScript Object Notation:Java对象表示法
JavaScript中对象的创建方法
{
name:"zhangsan",
age:23,
city:"北京"
}
JSON的创建格式
{
"name":"zhangsan",
"age":23,
"city":"北京"
}
对比发现
JSON的作用
{},里面的内容是键值对{user:"张三", age:"18", ...}[],里面的内容是一个元素["a", "zhangsan", 18, true]JSON本质是一个字符串,但是该字符串内容是有一定的格式要求
let 变量名 = '{"key": value, ...}';
JSON字符串的键要求必须使用双引号括起来,而且值要根据表示的类型来确定
JSON中的数据类型
示例
<script>
//定义一个对象
let user1 = {"name":"张无忌","age":18,"sex":"男"};
console.log(user1.age);
//定义json数组:描述张家的三代人
let arr = [
{"name":"张三丰","age":98,"sex":"男"},
{"name":"张翠山","age":38,"sex":"男"},
{"name":"张无忌","age":18,"sex":"男"}
];
console.log(arr[1].name);
//描述韦小宝: 7个老婆 一个师傅
let user2 = {
"name":"韦小宝",
"age":18,
"sex":"男",
"master":{
"name":"杨广武",
"age":29,
"sex":"中"
},
"wives":[
{"name":"双儿","sex":"女","age":22},
{"name":"建宁","sex":"女","age":16}
]
};
console.log(user2.wives[0].name);
</script>
parse(str) :将 JSON串转换为 js 对象。使用方式是: var jsObject = JSON.parse(jsonStr);
stringify(obj) :将 js 对象转换为 JSON 串。使用方式是:var jsonStr = JSON.stringify(jsObject)
代码演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
//1. 定义JSON字符串
var jsonStr = '{"name":"zhangsan","age":23,"addr":["北京","上海","西安"]}'
alert(jsonStr);
//2. 将 JSON 字符串转为 JS 对象
let jsObject = JSON.parse(jsonStr);
alert(jsObject)
alert(jsObject.name)
//3. 将 JS 对象转换为 JSON 字符串
let jsonStr2 = JSON.stringify(jsObject);
alert(jsonStr2)
</script>
</body>
</html>
Fastjson是阿里巴巴提供的一个Java语言编写的高性能完善的JSON库,是目前Java语言中最快的JSON库,可以实现java对象和JSON字符串的相互转换jacksonjson-libFastjson的使用步骤
1.导入坐标
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
2.Java对象转为JSON
String jsonStr = JSON.toJSONString(obj);
将 Java 对象转换为 JSON 串,只需要使用 Fastjson 提供的 JSON 类中的 toJSONString() 静态方法即可。
3.JSON字符串转成Java对象
User user = JSON.parseObject(jsonStr, User.class);
将 json 转换为 Java 对象,只需要使用 Fastjson 提供的 JSON 类中的 parseObject() 静态方法即可。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.coolman.pojo.User;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FastJsonTest {
@Test
// Java对象转JSON
public void testJavaBeanToJson() {
User user = new User(1, "coolman", "110", "123");
// 将Java对象转成json字符串
String jsonStr = JSON.toJSONString(user);
System.out.println("jsonStr = " + jsonStr);
// jsonStr = {"id":1,"name":"coolman","password":"123","phoneNumber":"110"}
}
@Test
// JSON转Java
public void testJsonToJavaBean() {
String jsonStr = "{\"id\":1,\"name\":\"coolman\",\"password\":\"123\",\"phoneNumber\":\"110\"}";
User user = JSON.parseObject(jsonStr, User.class);
System.out.println("user = " + user);
}
@Test
//Map转JSON
public void testMapToJson() {
HashMap<String, Object> map = new HashMap<>();
map.put("name","平平");
map.put("age",35);
map.put("sex","女");
//将map类型转成json字符串
String jsonStr = JSON.toJSONString(map);
System.out.println(jsonStr);//{"sex":"女","name":"平平","age":35}
}
@Test
//
public void testJsonToMap() {
String jsonStr = "{\"id\":1,\"name\":\"coolman\",\"password\":\"123\",\"phoneNumber\":\"110\"}";
Map map = JSON.parseObject(jsonStr, Map.class);
System.out.println(map);
}
@Test
//List转JSON
public void testListToJson(){
List<User> userList = new ArrayList<>();
User user = new User();
user.setName("杨广武");
user.setId(1);
user.setPassword("123");
user.setPhoneNumber("666");
User user1 = new User();
user1.setId(2);
user1.setName("hehe");
user1.setPassword("123");
user1.setPhoneNumber("777");
userList.add(user);
userList.add(user1);
//将list转成json字符串
String jsonStr = JSON.toJSONString(userList);
System.out.println("jsonStr = " + jsonStr);
//jsonStr = [{"id":1,"name":"杨广武","password":"123","phoneNumber":"666"},{"id":2,"password":"123","phoneNumber":"777"}]
}
@Test
public void testJsonToList() {
String jsonStr = "[{\"id\":1,\"name\":\"杨广武\",\"password\":\"123\",\"phoneNumber\":\"666\"},{\"id\":2,\"password\":\"123\",\"phoneNumber\":\"777\"}]";
List<User> users = JSON.parseArray(jsonStr, User.class);
System.out.println("users = " + users);
}
}
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳