javaEE(15)_Servlet过滤器
一、Filter简介
二、Filter开发入门
三、Filter的生命周期
四、FilterConfig接口
五、Filter案例:
1、解决全站乱码过滤器(含开发入门&Filter链&生命周期&FilterConfig)servlet3.0规范
@WebFilter(
urlPatterns = { "/ServletDemo1" },
initParams = {
@WebInitParam(name = "charset", value = "UTF-8", description = "编码")
})
public class FilterDemo1 implements Filter {
FilterConfig fConfig=null;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
System.out.println("FilterDemo1 doFilter 前!");
String charset = fConfig.getInitParameter("charset");
HttpServletRequest req = (HttpServletRequest)request;
req.setCharacterEncoding(charset); //这两句用来设置当servlet打印页面时的编码设置,实际开发中都是转发给jsp,由jsp来通过指令和meta标签进行设置
/*HttpServletResponse resp = (HttpServletResponse)response;
resp.setCharacterEncoding(charset);
resp.setContentType(charset);*/ chain.doFilter(request, response);
System.out.println("FilterDemo1 doFilter 后!");
} public void init(FilterConfig fConfig) {
System.out.println("FilterDemo1 init!");
this.fConfig = fConfig;
} public void destroy() {
System.out.println("FilterDemo1 destroy!");
}
}
@WebFilter("/ServletDemo1")
public class FilterDemo2 implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
System.out.println("FilterDemo2 doFilter 前!");
chain.doFilter(request, response);
System.out.println("FilterDemo2 doFilter 后!");
} public void init(FilterConfig fConfig) throws ServletException {
System.out.println("FilterDemo2 init!");
} public void destroy() {
System.out.println("FilterDemo2 destroy!");
}
}
@WebServlet("/ServletDemo1")
public class ServletDemo1 extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) {
String name = request.getParameter("username");
System.out.println("ServletDemo1 doget! name="+name);
} protected void doPost(HttpServletRequest request, HttpServletResponse response) {
this.doGet(request, response);
} public void init(ServletConfig config) throws ServletException {
System.out.println("ServletDemo1 init!");
} public void destroy() {
System.out.println("ServletDemo1 destroy!");
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/ServletDemo1 " method="post">
<input name="username" />
<input type="submit" value="提交"/>
</form>
</body>
</html>
运行结果:
1、当服务器启动时:
FilterDemo2 init!
FilterDemo1 init!
首先初始化FilterDemo2,与调用doFilter的顺序刚好相反(doFilter的调用顺序与类的名称相关).
2、当在demo1.jsp中输入中文点击提交时:
ServletDemo1 init!
FilterDemo1 doFilter 前!
FilterDemo2 doFilter 前!
ServletDemo1 doget! name=王维
FilterDemo2 doFilter 后!
FilterDemo1 doFilter 后!
3、当服务器关闭或者项目重新发布时:
ServletDemo1 destroy!
FilterDemo2 destroy!
FilterDemo1 destroy!
如上所示的servlet过滤器可以实现当访问说有的servlet时,在它之前进行编码设置.
2、控制浏览器缓存页面中的静态资源,禁止浏览器缓存动态页面
<!--测试jsp页面,此页面首次访问时共会向服务器发送3次请求 -->
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<link rel="stylesheet" type="text/css" href="/Filter/css/1.css">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>noCache</title>
</head>
<body>
hello
<img id="img1" alt="ss" src="/Filter/image/1.png">
</body>
</html>
//控制jsp不缓存的Filter,我们的jsp都是由servlet forward来的
@WebFilter(dispatcherTypes = {DispatcherType.FORWARD }, urlPatterns = { "*.jsp" })//ps备注
public class NoCacheFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain){
HttpServletResponse resp = (HttpServletResponse)response; //注意一个是setDateHeader另两个是setHeader
resp.setDateHeader("Expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache"); chain.doFilter(request, response);
} public void destroy() {
}
public void init(FilterConfig arg0) throws ServletException {
}
}
//控制css文件和图片缓存的Filter
@WebFilter(
urlPatterns={"*.css","*.png"},//一个Filter可对应多个url映射,类似Servlet
initParams = {
@WebInitParam(name = "cssExpires", value = "6000", description = "css文件缓存时间"),
@WebInitParam(name = "imageExpires", value = "6000", description = "图片文件缓存时间")
})
public class CacheFilter implements Filter {
FilterConfig fConfig=null;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain){
HttpServletResponse resp = (HttpServletResponse)response;
HttpServletRequest req = (HttpServletRequest)request; String cssExpires = fConfig.getInitParameter("cssExpires");
String imageExpires = fConfig.getInitParameter("imageExpires"); String uri = req.getRequestURI();
if(uri.endsWith("css")){
//这里注意是setDateheader不是setHeader
resp.setDateHeader("Expires",System.currentTimeMillis()+Long.parseLong(cssExpires));
}else{
resp.setDateHeader("Expires",System.currentTimeMillis()+Long.parseLong(imageExpires));
}
chain.doFilter(request, response);
} public void init(FilterConfig fConfig) throws ServletException {
this.fConfig=fConfig;
}
public void destroy() {
}
}
ps:1、Ctrl+F5强制刷新的话,不管浏览器有没有缓存都会向服务器重新请求.
2、<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST.用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截.
<dispatcher> 子元素可以设置的值及其意义:
REQUEST:当用户直接访问页面时,Web容器将会调用过滤器.如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用.
INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用.除此之外,该过滤器不会被调用.
FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用.
ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用.除此之外,过滤器不会被调用.
用法实例:
<filter-mapping>
<filter-name>testFilter</filter-name>
<url-pattern>/test.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>testFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
3、实现用户自动登陆的过滤器 *代码非常经典
<!--登陆界面 -->
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'login.jsp' starting page</title>
</head> <body>
<form action="${pageContext.request.contextPath }/servlet/LoginServlet" method="post">
用户名:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
有效期:
1分钟<input type="radio" name="time" value="${1*60 }">
5分钟<input type="radio" name="time" value="${5*60 }">
10分钟<input type="radio" name="time" value="${10*60 }">
<br/>
<input type="submit" value="登陆">
</form>
</body>
</html> //登陆Servlet
public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response){ String username = request.getParameter("username");
String password = request.getParameter("password"); BusinessService service = new BusinessService();
User user = service.login(username, password);
if (user == null) {
request.setAttribute("message", "用户名或密码错误!!");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
} request.getSession().setAttribute("user", user); // 给客户机发送自动登陆的 cookie
//把username回写给cookie,Filter需要通过username拿到用户信息,校验cookie带的md5和服务器算出的MD5是否一致,判断cookie有没有被修改
int expirestime = Integer.parseInt(request.getParameter("time"));
// autologin=username:expirestime:md5(password:expirestime:username)
Cookie cookie = makeCookie(user, expirestime);
response.addCookie(cookie);
response.sendRedirect("/day19/index.jsp");
} public Cookie makeCookie(User user, int expirestime) {
long currenttime = System.currentTimeMillis();
String cookieValue = user.getUsername() + ":" + (currenttime + expirestime * 1000) + ":"
+ md5(user.getUsername(), user.getPassword(), (currenttime + expirestime * 1000));
Cookie cookie = new Cookie("autologin", cookieValue);
cookie.setMaxAge(expirestime);
cookie.setPath("/day19");
return cookie;
} private String md5(String username, String password, long expirestime) {
try {
String value = password + ":" + expirestime + ":" + username;
MessageDigest md = MessageDigest.getInstance("md5");
byte md5[] = md.digest(value.getBytes());
BASE64Encoder encode = new BASE64Encoder();
return encode.encode(md5);
} catch (Exception e) {
throw new RuntimeException(e);
}
} public void doPost(HttpServletRequest request, HttpServletResponse response) throws Exception {
doGet(request, response);
} } //自动登录拦截器
@WebFilter("*.*") // 访问所有资源都进行拦截
public class AutoLoginFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp; // 1.先检查用户是否已登陆,没登陆才自动登陆
User user = (User) request.getSession().getAttribute("user");
if (user != null) {
chain.doFilter(request, response);
return;
} // 2.没登陆,再执行自动登陆逻辑 // 看用户有没有带自动登陆的cookie
Cookie autoLoginCookie = null;
Cookie cookies[] = request.getCookies();
for (int i = 0; cookies != null && i < cookies.length; i++) {
if (cookies[i].getName().equals("autologin")) {
autoLoginCookie = cookies[i];
}
}
if (autoLoginCookie == null) {
chain.doFilter(request, response);
return;
} // 用户带了自动登陆的cookie,则先检查cookie的有效期
String values[] = autoLoginCookie.getValue().split("\\:");
if (values.length != 3) {
chain.doFilter(request, response);
return;
}
long expirestime = Long.parseLong(values[1]);
if (System.currentTimeMillis() > expirestime) {
chain.doFilter(request, response);
return;
} // 代表cookie时间有效,再检查cookie的有效性
String username = values[0];
String client_md5 = values[2]; BusinessService service = new BusinessService();
user = service.findUser(username);
if (user == null) {
chain.doFilter(request, response);
return;
}
//// autologin=username:expirestime:md5(password:expirestime:username)
String server_md5 = md5(user.getUsername(), user.getPassword(), expirestime);
if (!server_md5.equals(client_md5)) {
chain.doFilter(request, response);
return;
} // 执行登陆
request.getSession().setAttribute("user", user);
chain.doFilter(request, response);
} private String md5(String username, String password, long expirestime) {
try {
String value = password + ":" + expirestime + ":" + username;
MessageDigest md = MessageDigest.getInstance("md5");
byte md5[] = md.digest(value.getBytes());
BASE64Encoder encode = new BASE64Encoder();
return encode.encode(md5);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void destroy() {
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
六、Decorator设计模式
由于开发人员在filter中可以得到代表用户请求和响应的request、response对象,因此在编程中可以使用Decorator(装饰器)模式对request、response对象进行包装,再把包装对象传给目标资源,从而实现一些特殊需求.
public class CharacterEncodingFilter2 implements Filter { public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp; request.setCharacterEncoding("UTF-8"); //只能解决post乱码问题 chain.doFilter(new MyRequest(request), response);
} class MyRequest extends HttpServletRequestWrapper{ private HttpServletRequest request;
public MyRequest(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) { String value = this.request.getParameter(name);
if(!request.getMethod().equalsIgnoreCase("get")){
return value;
}
if(value==null){
return null;
}
try {
return value = new String(value.getBytes("iso8859-1"),request.getCharacterEncoding());
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
public void destroy() {
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
例2、使用Decorator模式包装request对象,实现html标签转义功能(Tomcat服务器中提供了转义html标签的工具类),对客户端提交的文本进行转义.
public class HtmlFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp; chain.doFilter(new MyRequest(request), response);
} class MyRequest extends HttpServletRequestWrapper{
private HttpServletRequest request;
public MyRequest(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) { String value = this.request.getParameter(name);
if(value==null){
return null;
}
return filter(value);
} public String filter(String message) { if (message == null)
return (null); char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
StringBuffer result = new StringBuffer(content.length + 50);
for (int i = 0; i < content.length; i++) {
switch (content[i]) {
case '<':
result.append("<");
break;
case '>':
result.append(">");
break;
case '&':
result.append("&");
break;
case '"':
result.append(""");
break;
default:
result.append(content[i]);
}
}
return (result.toString());
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
}
例3、词汇过滤器
其实和html标签转义功能完全类似,使用装饰器模式,拦截getParameter方法,当在servlet中调用getParameter方法时,实际调用的是我修改过的getParameter方法,该方法对词汇进行了过滤.
response对象的增强最经典案例-压缩响应如下:
2、应用HttpServletResponseWrapper对象,压缩响应正文内容.思路:
例1、没有实现全站式的压缩
//压缩输出
public class ServletDemo2 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { String data = "aaaaaaaa"; ByteArrayOutputStream bout = new ByteArrayOutputStream();//缓存字节流
GZIPOutputStream gout = new GZIPOutputStream(bout);
gout.write(data.getBytes());
gout.close();//确保写入缓存流成功 byte gzip[] = bout.toByteArray();
response.setHeader("content-encoding", "gzip");
response.setHeader("content-length", gzip.length + ""); response.getOutputStream().write(gzip);
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
例2、全站式压缩实现
//giz压缩过滤器
public class GzipFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
MyResponse myresponse = new MyResponse(response); //response.getwriter response.getOutputStream
chain.doFilter(request, myresponse); //取出缓冲的数据压缩后输出
byte out[] = myresponse.getBuffer(); //得到目标资源的输出
System.out.println("压之前:" + out.length); byte gzipout[] = gzip(out);
System.out.println("压之后:" + gzipout.length); response.setHeader("content-encoding", "gzip");
response.setHeader("content-length", gzipout.length + "");
response.getOutputStream().write(gzipout);
} public byte[] gzip(byte b[]) throws IOException{ ByteArrayOutputStream bout = new ByteArrayOutputStream();
GZIPOutputStream gout = new GZIPOutputStream(bout);
gout.write(b);
gout.close();
return bout.toByteArray();
} class MyResponse extends HttpServletResponseWrapper{
private ByteArrayOutputStream bout = new ByteArrayOutputStream();
private PrintWriter pw; private HttpServletResponse response;
public MyResponse(HttpServletResponse response) {
super(response);
this.response = response;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new MyServletOutputStream(bout); //myresponse.getOutputStream().write("hahah");
} @Override
public PrintWriter getWriter() throws IOException {
pw = new PrintWriter(new OutputStreamWriter(bout,response.getCharacterEncoding()));
return pw; //MyResponse.getWriter().write("中国");
}
public byte[] getBuffer(){
if(pw!=null){
pw.close();
}
return bout.toByteArray();
}
} class MyServletOutputStream extends ServletOutputStream{ private ByteArrayOutputStream bout;
public MyServletOutputStream(ByteArrayOutputStream bout){
this.bout = bout;
}
@Override
public void write(int b) throws IOException {
bout.write(b);
}
}
public void destroy() {
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
public class GzipServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { String data = "中国";
response.getOutputStream().write(data.getBytes("UTF-8"));
request.getRequestDispatcher("/index.jsp").forward(request, response);
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
web.xml配置
<filter>
<filter-name>GzipFilter</filter-name>
<filter-class>cn.itcast.web.filter.example.GzipFilter</filter-class>
</filter> <filter-mapping>
<filter-name>GzipFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping> <filter-mapping>
<filter-name>GzipFilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping> <filter-mapping>
<filter-name>GzipFilter</filter-name>
<url-pattern>*.js</url-pattern>
</filter-mapping>
ps:gzip一般压缩文本类型的数据,对图片视频等压缩率较低.
***有一点要注意,当servlet中以forward方式转发给另一个servlet时,实际是通知tomcat去调用另一个servlet,这其中如果有拦截器的话会执行.
七、实用案例-缓存数据到内存
//可以配置给几个指定的servlet
public class WebCacheFilter implements Filter { private Map<String,byte[]> map = new HashMap(); public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp; //1.得到用户想访问的资源(uri)
String uri = request.getRequestURI(); //2.看map集合中是否保存了该资源的数据
byte b[] = map.get(uri); //3.如果保存了,则直接取数据打给浏览器
if(b!=null){
response.getOutputStream().write(b);
return;//servlet就不执行了
} //4.如果没有保存数据,则放行让目标资源执行,这时还需写一个response的包装类,捕获目标资源的输出
MyResponse my = new MyResponse(response);
chain.doFilter(request, my);
byte data[] = my.getBuffer(); //5.以资源uri为关键字,打资源的数据保存map集合中,以备于下次访问
map.put(uri, data); //6.输出数据给浏览器
response.getOutputStream().write(data);
} class MyResponse extends HttpServletResponseWrapper{
private ByteArrayOutputStream bout = new ByteArrayOutputStream();
private PrintWriter pw; private HttpServletResponse response;
public MyResponse(HttpServletResponse response) {
super(response);
this.response = response;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new MyServletOutputStream(bout); //myresponse.getOutputStream().write("hahah");
} @Override
public PrintWriter getWriter() throws IOException {
pw = new PrintWriter(new OutputStreamWriter(bout,response.getCharacterEncoding()));
return pw; //MyResponse.getWriter().write("中国");
}
public byte[] getBuffer(){
if(pw!=null){
pw.close();
}
return bout.toByteArray();
}
} class MyServletOutputStream extends ServletOutputStream{ private ByteArrayOutputStream bout;
public MyServletOutputStream(ByteArrayOutputStream bout){
this.bout = bout;
}
@Override
public void write(int b) throws IOException {
bout.write(b);
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
}
ps:过滤器经典案例,权限系统,略。
javaEE(15)_Servlet过滤器的更多相关文章
- javaEE(3)_servlet基础
一.Servlet简介 1.Servlet是sun公司提供的一门用于开发动态web资源的技术,Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序 ...
- 15 Filter过滤器和Listener监听器
1.Filter:过滤器 (1) 概念:生活中的过滤器:净水器,空气净化器,土匪.web中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能.过滤器的作用:一般用于完成通用的 ...
- JavaEE(15) - JPA实体继承
1. 实体继承映射的三种策略 #1. 整个类层次对应一张表 #2. 连接子类 #3. 每个具体类对应一张表 2. 使用抽象实体 3. 使用非实体父类 4. 重定义子类实体的外键列 ---------- ...
- javaEE(16)_Servlet监听器
一.监听器原理 1.监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行. 2.监听器典型案例 ...
- JavaEE基础:过滤器、监听器、拦截器,应用...
写在前面说起Java和C++,很容易想到让人疯狂的指针,Java使用了内存动态分配和垃圾回收技术,让我们从C++的各种指针问题中摆脱出来,更加专心于业务逻辑,不过如果我们需要深入了解java的JVM相 ...
- JSP-12-使用过滤器和监听器
1 什么是过滤器及其工作方式 向Web应用程序的请求和响应添加功能的Web组建 过滤器可以统一的集中处理请求和响应 15.2 过滤器的实现 新建 filter ,注意此时是在 src中建立的(同cla ...
- Spring Security入门(1-12)Spring Security 的过滤器机制
Servlet过滤器被用来拦截用户请求来进行请求之前或之后的处理,或者干脆重定向这个请求,这取决于servlet过滤器的功能. Servlet过滤器处理之后的目标servlet是 MVC 分发web ...
- 设计模式系列之过滤器模式(Chriteria Pattern)
过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来.这种类 ...
- 谈谈JavaEE的mvc模式及典型的三层架构
首先,向读者介绍一下mvc架构,mvc是一种源于桌面程序的架构模式,它的基本思想是把程序界面和业务逻辑分开,这样便于软件的后期维护,同时也方便开发时期分工及管理,mvc有很多有点所以现在已经被广泛的应 ...
随机推荐
- 聊聊IT行业加班的问题
IT行业(包括互联网行业)是快速发展的行业,有时候一家公司同时可能要开发多个项目,并发进行,在公司开发人员相对固定的情况下,要想在指定的时间内完成项目谈何容易. 项目多.任务重.需求的不明确.技术难关 ...
- windows 修改鼠标滚轮自然滚动
在mac 上玩习惯了,使用windows 时的鼠标实在觉得别扭,在网上百度了一下,找到一个方法,这里记录一下 1 打开windows 的控制面板,点击“硬件和声音” 2 点击“鼠标” 3 然后点击上面 ...
- PJzhang:python基础入门的7个疗程-one
猫宁!!! 参考链接:易灵微课-21天轻松掌握零基础python入门必修课-售价29元人民币 https://www.liaoxuefeng.com/wiki/1016959663602400 安全从 ...
- 面向对象-mixin设计模式的应用(多继承应用场景)
什么是设计模式? 设计模式只是一种开发思想.不是什么固定的格式. 前人的好的思想,我们后人拿过来用! mixin设计模式: 1.mixin设计迷失可以在不对类的内容的修改前提下,扩展类的功能(添加父类 ...
- gcd(2018.10.24)
良心题,暴力枚举即可. 代码: #include<cstdio> #include<cmath> #include<algorithm> using namespa ...
- A. Office Keys ( Codeforces Round #424 (Div. 1, rated, based on VK Cup Finals) )
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm& ...
- 关于JS中的call()方法和apply() 暂时只接触到call() 等接触到apply()再回头来看
1. 每个函数都包含两个非继承而来的方法:call()方法和apply()方法. 2. 相同点:这两个方法的作用是一样的. 都是在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖 ...
- git合并某次提交到某个分支
有的时候,在develop分支开发,是大家公用的开发分支,但是只想合并自己提交的到master,如何操作呢?那就要用cherry-pick了. 语法 git cherry-pick commitid ...
- [poj 2104] K-th Number【主席树】
传送门:http://poj.org/problem?id=2104 保存模版. #include <cstdio> #include <algorithm> #include ...
- POJ-3275:Ranking the Cows(Floyd、bitset)
Ranking the Cows Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 3301 Accepted: 1511 ...