用过springmvc的可能都知道,要集成springmvc需要在web.xml中加入一个跟随web容器启动的DispatcherServlet,然后由该servlet初始化一些东西,然后所有的web请求都被这个servlet接管。所以自己写mvc的关键就是弄懂这个servlet干了啥。先分析一下springmvc的功能,首先我们写一个接口,就是写一个Controller,然后里面写一个方法,在类或者方法里面使用@RequestMapping直接修饰,当该注解对应的path被请求时,会按照指定格式传入参数并调用该方法,然后按照指定格式将调用的结果写出到向浏览器的输出流中(@ResponseBody),或者转发到jsp,再去由jsp转换生成的servlet去将结果写出到输出流(默认的请求转发),或者重定向到指定的jsp(return "redirect:/test.jsp"等。上面仅仅使用jsp举例子,不代表springmvc只支持使用jsp渲染。但是我们自己写的mvc只是为了演示整个流程和若干细节,并不能全面重写springmvc我也没那个能力重写,所以页面层只用jsp。
  详细分析下写一个mvc的流程:第一:我们也可以使用一个servlet将前端所有请求都接管到一个servlet中去(这里其实filter,servlet都可以实现,比如strus2采用filter接管,springmvc采用servlet,原理大同小异),第二:这个servlet是随着容器自启动,所以需要配置load-on-startup,然后我们在这个servlet的init方法里面可以扫描指定的包(扫描哪些包,可以通过servlet在web.xml中的init-param配置),加载一些注解并将注解配置的属性和类,方法对象的关系保存在一些map中,第三:当页面访问任意后端接口时,最终会经过doGet或者doPost(上层是service方法,为了方便不用service方法),我们可以在这两个方法中根据请求的url路径去找到对应的Controller类和Method对象,然后从请求中拿出参数传入方法需要的参数,得到方法执行的结果,最后根据方法里面指定的返回格式(@ResponseBody这种),或者请求转发,或者重定向做处理。废话不多说,直接上代码。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>mymvc</display-name>
<servlet>
<servlet-name>dispacher</servlet-name>
<servlet-class>com.rd.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>package</param-name>
<param-value>com.rd.controller</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispacher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
package com.rd.servlet;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern; import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import com.rd.annotation.Path;
import com.rd.annotation.RespJson;
import com.rd.util.JsonUtil;
import com.rd.util.MethodUtil;
import com.rd.util.ScanClassUtil; /**
* 类似springmvc的将请求全部纳入控制范围的servlet
* @author rongdi
* @date 2017年9月20日 下午1:58:26
*/
public class DispatcherServlet extends HttpServlet { private static final long serialVersionUID = 1L; //path和Class的映射
private final static Map<String, Class<?>> classMap = new HashMap<String, Class<?>>(); //path和Method的映射
private final static Map<String, Method> methodMap = new HashMap<String, Method>(); //存放被@RespJson修饰的类
private final static Set<Class<?>> classRespJsons = new HashSet<Class<?>>(); //存放被@RespJson修饰的方法
private final static Set<Method> methodRespJsons = new HashSet<Method>(); @Override
public void init(ServletConfig config) throws ServletException {
System.out.println("---DispatcherServlet初始化开始---");
//获取web.xml中配置的要扫描的包
String basePackage = config.getInitParameter("package");
//配置了多个包
if (basePackage.indexOf(",")>0) {
//按逗号进行分隔
String[] packageNameArr = basePackage.split(",");
for (String packageName : packageNameArr) {
add2ClassMap(packageName);
}
}else {
add2ClassMap(basePackage);
}
System.out.println("----DispatcherServlet初始化结束---");
} /**
* 将被注解修饰的类
* @param packageName
*/
private void add2ClassMap(String packageName){
Set<Class<?>> setClasses = ScanClassUtil.getClasses(packageName);
for (Class<?> clazz :setClasses) {
String pathAttrValue = null;
//判断类被注解修饰
if (clazz.isAnnotationPresent(Path.class)) {
//获取path的Annotation的实例
Path pathInstance = clazz.getAnnotation(Path.class);
//获取Annotation的实例的value属性的值
pathAttrValue = pathInstance.value();
if (StringUtils.isNotEmpty(pathAttrValue)) {
pathAttrValue = handPathStr(pathAttrValue);
classMap.put(pathAttrValue, clazz);
}
}
if(clazz.isAnnotationPresent(RespJson.class)) {
classRespJsons.add(clazz);
}
//判断方法被注解修饰
Method[] methods = clazz.getMethods();
for(Method m:methods) {
//判断方法被注解修饰
if(m.isAnnotationPresent(Path.class)) {
//获取path的Annotation的实例
Path pathInstance = m.getAnnotation(Path.class);
//获取Annotation的实例的value属性的值
String methodPathValue = pathInstance.value();
if (StringUtils.isNotEmpty(methodPathValue)) {
methodPathValue = handPathStr(methodPathValue);
pathAttrValue = handPathStr(pathAttrValue);
methodMap.put(pathAttrValue+methodPathValue, m);
}
}
if(m.isAnnotationPresent(RespJson.class)) {
methodRespJsons.add(m);
}
}
}
} /**
* 处理一下路径,前面后面的斜杠
* @param pathStr
* @return
*/
private String handPathStr(String pathStr) {
if(pathStr.endsWith("/")) {
pathStr = pathStr.substring(0,pathStr.length()-1);
}
if(!pathStr.startsWith("/")) {
pathStr = "/"+pathStr;
}
return pathStr;
} @Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Map<String,String[]> params = request.getParameterMap();
String url = request.getRequestURI();
//当请求根路径是,请求转发到首页
if("/".equals(url)) {
request.getRequestDispatcher("/index.jsp").forward(request, response);
return;
}
if("/favicon.ico".equals(url)) {
return;
}
Method m = null;
if(methodMap.containsKey(url)) {
m = methodMap.get(url);
} else {
//这个过程,其实可以优化,如果存在通配符匹配,不用每次都循环匹配,可以缓存起来,第二次直接用,这里暂时忽略优化问题
Set<String> urls = methodMap.keySet();
for(String murl:urls) {
String reg = "^"+murl.replace("*", ".*?")+"$";
if(Pattern.matches(reg, url)) {
m = methodMap.get(murl);
break;
}
}
}
if(m == null) {
throw new ServletException("没有找到与路径:"+url+"对应的处理方法");
} try {
/**
* 这里需要获取参数名,jdk1.8之后可以直接直接反射获取,条件比较恶心,需要开启开关
* 如下直接使用javassist字节码工具类实现,也可以用asm等其他工具
*/
String[] paramNames = MethodUtil.getAllParamaterName(m);
List<String> paramValues = new ArrayList<String>();
for(String paramName:paramNames) {
if(params.get(paramName) == null) {
paramValues.add(null);
} else {
paramValues.add(params.get(paramName)[0]);
} }
/**
* 调用方法所在类的默认构造方法,生成执行方法的对象(springmvc里的这个对象是单例的,这里为了省事,每次都new一个出来),
* 然后执行方法,返回结果
*/
Class<?> cla = m.getDeclaringClass();
Object result = m.invoke(cla.newInstance(), paramValues.toArray());
/**
* 如果方法返回类型为 void,则该调用结果返回 null,如果返回值为void,则直接跳转到同路径的jsp页面上,
* 为了简单起见这里后缀写死.jsp,实际上springmvc是支持配置ViewResolver,
* 可以指定请求转发或者重定向所在的界面层的前缀和后缀。
*/
if(result == null) {
request.getRequestDispatcher(url+".jsp").forward(request, response);
}
/**
* 这里springmvc默认是请求转发到jsp
* 为了方便这里直接根据修饰返回类型的注解,确定用哪种方式序列化,
*/
if(classRespJsons.contains(cla) || methodRespJsons.contains(m)) {
result = JsonUtil.serialize(result);
//输出json到浏览器
response.getWriter().print(result);
} else if(result.toString().startsWith("redirect:")) { //重定向
//去掉前缀就是重定向到的路径,实际上这里不严谨,应该加上一个项目的上下文路径
response.sendRedirect(result.toString().substring(9)+".jsp");
} else { //请求转发
request.getRequestDispatcher(result.toString()+".jsp").forward(request, response);
} } catch (Exception e) {
e.printStackTrace();
}
} @Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
} public static void main(String[] args) {
String url = "/test/a";
String reg = "^/test/.*?$";
System.out.println(Pattern.matches(reg, url));
System.out.println(Long.class); }
}
package com.rd.controller;

import java.util.HashMap;
import java.util.Map; import com.rd.annotation.Path;
import com.rd.annotation.RespJson; @Path(value="/test")
public class TestController { @Path(value="/text")
public void text() {
} @Path(value="/redirect")
public String redirect(String a) { return "redirect:/test/redirect";
} @Path(value="/json")
@RespJson
public Map json(String a) {
return new HashMap(){{put("a",a);}};
} }
package com.rd.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Path { //访问的匹配路径
String value(); }
package com.rd.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface RespJson { }
package com.rd.util;

import java.util.HashMap;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; public class JsonUtil { private static ObjectMapper mapper; static {
mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
false);
} public static String serialize(Object obj) throws Exception { if (obj == null) {
throw new IllegalArgumentException("obj should not be null");
}
return mapper.writeValueAsString(obj);
} public static void main(String[] args) throws Exception {
System.out.println(serialize(new HashMap(){{put("name","zhangsan");}}));
}
}
package com.rd.util;
import java.lang.reflect.Method; import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo; /**
* 使用javassist的方法工具
* @author rongdi
* @date 2017年9月20日 上午11:21:29
*/
public class MethodUtil { public static String[] getAllParamaterName(Method method)
throws NotFoundException {
Class<?> clazz = method.getDeclaringClass();
ClassPool pool = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(MethodUtil.class);
pool.insertClassPath(classPath);
CtClass clz = pool.get(clazz.getName());
CtClass[] params = new CtClass[method.getParameterTypes().length];
for (int i = 0; i < method.getParameterTypes().length; i++) {
params[i] = pool.getCtClass(method.getParameterTypes()[i].getName());
}
CtMethod cm = clz.getDeclaredMethod(method.getName(), params);
MethodInfo methodInfo = cm.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute
.getAttribute(LocalVariableAttribute.tag);
int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
String[] paramNames = new String[cm.getParameterTypes().length];
for (int i = 0; i < paramNames.length; i++) {
paramNames[i] = attr.variableName(i + pos);
}
return paramNames;
} }
package com.rd.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties; /**
* @author rongdi
* @date 2017年9月16日 下午3:36:08
*/
public class PropertyUtil { private static Properties props; synchronized static private void loadProps() {
props = new Properties();
InputStream in = null; try {
try {
String path = getJarDir()+"/application.properties";
in = new FileInputStream(path);
} catch(Exception e){
in = PropertyUtil.class.getClassLoader().getResourceAsStream("application.properties");
}
props.load(in);
} catch (FileNotFoundException e) {
//logger.error("application.properties文件未找到");
} catch (IOException e) {
//logger.error("出现IOException");
} finally {
try {
if (null != in) {
in.close();
}
} catch (IOException e) {
//logger.error("application.properties文件流关闭出现异常");
}
}
} public static String getProperty(String key) {
if (null == props) {
loadProps();
}
return props.getProperty(key);
} public static String getProperty(String key, String defaultValue) {
if (null == props) {
loadProps();
}
return props.getProperty(key, defaultValue);
} /**
* 获取jar绝对路径
*
* @return
*/
public static String getJarPath() {
File file = getFile();
if (file == null)
return null;
return file.getAbsolutePath();
} /**
* 获取jar目录
*
* @return
*/
public static String getJarDir() {
File file = getFile();
if (file == null)
return null;
return getFile().getParent();
} /**
* 获取jar包名
*
* @return
*/
public static String getJarName() {
File file = getFile();
if (file == null)
return null;
return getFile().getName();
} /**
* 获取当前Jar文件
*
* @return
*/
private static File getFile() {
// 关键是这行...
String path = PropertyUtil.class.getProtectionDomain().getCodeSource()
.getLocation().getFile();
try {
path = java.net.URLDecoder.decode(path, "UTF-8"); // 转换处理中文及空格
} catch (java.io.UnsupportedEncodingException e) {
return null;
}
return new File(path);
}
}
package com.rd.util;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile; /**
* 扫描字节码工具类
* @author rongdi
* @date 2017年9月19日 下午4:13:19
*/
public class ScanClassUtil { /**
* 从包package中获取所有的Class
* @param pack
* @return
*/
public static Set<Class<?>> getClasses(String pack) { // 第一个class类的集合
Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
// 是否循环迭代
boolean recursive = true;
// 获取包的名字 并进行替换
String packageName = pack;
String packageDirName = packageName.replace('.', '/');
// 定义一个枚举的集合 并进行循环来处理这个目录下的things
Enumeration<URL> dirs;
try {
dirs = Thread.currentThread().getContextClassLoader().getResources(
packageDirName);
// 循环迭代下去
while (dirs.hasMoreElements()) {
// 获取下一个元素
URL url = dirs.nextElement();
// 得到协议的名称
String protocol = url.getProtocol();
// 如果是以文件的形式保存在服务器上
if ("file".equals(protocol)) {
System.err.println("file类型的扫描");
// 获取包的物理路径
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
// 以文件的方式扫描整个包下的文件 并添加到集合中
findAndAddClassesInPackageByFile(packageName, filePath,recursive, classes);
} else if ("jar".equals(protocol)) {
// 如果是jar包文件
// 定义一个JarFile
System.err.println("jar类型的扫描");
JarFile jar;
try {
// 获取jar
jar = ((JarURLConnection) url.openConnection())
.getJarFile();
// 从此jar包 得到一个枚举类
Enumeration<JarEntry> entries = jar.entries();
// 同样的进行循环迭代
while (entries.hasMoreElements()) {
// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
JarEntry entry = entries.nextElement();
String name = entry.getName();
// 如果是以/开头的
if (name.charAt(0) == '/') {
// 获取后面的字符串
name = name.substring(1);
}
// 如果前半部分和定义的包名相同
if (name.startsWith(packageDirName)) {
int idx = name.lastIndexOf('/');
// 如果以"/"结尾 是一个包
if (idx != -1) {
// 获取包名 把"/"替换成"."
packageName = name.substring(0, idx).replace('/', '.');
}
// 如果可以迭代下去 并且是一个包
if ((idx != -1) || recursive) {
// 如果是一个.class文件 而且不是目录
if (name.endsWith(".class") && !entry.isDirectory()) {
// 去掉后面的".class" 获取真正的类名
String className = name.substring(
packageName.length() + 1, name
.length() - 6);
try {
// 添加到classes
classes.add(Class.forName(packageName + '.'
+ className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
} return classes;
} /**
* 以文件的形式来获取包下的所有Class
*
* @param packageName
* @param packagePath
* @param recursive
* @param classes
*/
public static void findAndAddClassesInPackageByFile(String packageName,
String packagePath, final boolean recursive, Set<Class<?>> classes) {
// 获取此包的目录 建立一个File
File dir = new File(packagePath);
// 如果不存在或者 也不是目录就直接返回
if (!dir.exists() || !dir.isDirectory()) {
// log.warn("用户定义包名 " + packageName + " 下没有任何文件");
return;
}
// 如果存在 就获取包下的所有文件 包括目录
File[] dirfiles = dir.listFiles(new FileFilter() {
// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
public boolean accept(File file) {
return (recursive && file.isDirectory())
|| (file.getName().endsWith(".class"));
}
});
// 循环所有文件
for (File file : dirfiles) {
// 如果是目录 则继续扫描
if (file.isDirectory()) {
findAndAddClassesInPackageByFile(packageName + "."
+ file.getName(), file.getAbsolutePath(), recursive,
classes);
} else {
// 如果是java类文件 去掉后面的.class 只留下类名
String className = file.getName().substring(0,
file.getName().length() - 6);
try {
// 添加到集合中去
//classes.add(Class.forName(packageName + '.' + className));
classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
} catch (ClassNotFoundException e) {
// log.error("添加用户自定义视图类错误 找不到此类的.class文件");
e.printStackTrace();
}
}
}
}
}
<properties>
<project.deploy>deploy</project.deploy>
<jackson.version>2.5.4</jackson.version>
</properties> <dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.21.0-GA</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency> </dependencies>

完整代码百度云地址(不要吐槽要放git啥的,我屌丝一个,不用那么高大上的东西):https://pan.baidu.com/s/1mi24Lbq

自己动手实现mvc框架的更多相关文章

  1. 自己动手写PHP MVC框架

    自己动手写PHP MVC框架 来自:yuansir-web.com / yuansir@live.cn 代码下载: https://github.com/yuansir/tiny-php-framew ...

  2. 自己动手写Spring框架--IOC、MVC

    对于一名Java开发人员,我相信没有人不知道 Spring 框架,而且也能够轻松就说出 Spring 的特性-- IOC.MVC.AOP.ORM(batis). 下面我想简单介绍一下我写的轻量级的 S ...

  3. 自己动手写一个简单的MVC框架(第二版)

    一.ASP.NET MVC核心机制回顾 在ASP.NET MVC中,最核心的当属“路由系统”,而路由系统的核心则源于一个强大的System.Web.Routing.dll组件. 在这个System.W ...

  4. 自己动手做Web框架—MVC+Front Controller

    在我前面一篇博文<逃脱Asp.Net MVC框架的枷锁,使用Razor视图引擎>发表之后,很多人关心,脱离了之后怎么办?那么这可以说是它的续篇了. 同时,这也是eLiteWeb开源软件的一 ...

  5. MVC系列——MVC源码学习:打造自己的MVC框架(四:了解神奇的视图引擎)

    前言:通过之前的三篇介绍,我们基本上完成了从请求发出到路由匹配.再到控制器的激活,再到Action的执行这些个过程.今天还是趁热打铁,将我们的View也来完善下,也让整个系列相对完整,博主不希望烂尾. ...

  6. MVC系列——MVC源码学习:打造自己的MVC框架(三:自定义路由规则)

    前言:上篇介绍了下自己的MVC框架前两个版本,经过两天的整理,版本三基本已经完成,今天还是发出来供大家参考和学习.虽然微软的Routing功能已经非常强大,完全没有必要再“重复造轮子”了,但博主还是觉 ...

  7. 从零开始学 Java - 搭建 Spring MVC 框架

    没有什么比一个时代的没落更令人伤感的了 整个社会和人都在追求创新.进步.成长,没有人愿意停步不前,一个个老事物慢慢从我们生活中消失掉真的令人那么伤感么?或者说被取代?我想有些是的,但有些东西其实并不是 ...

  8. 【WEB】初探Spring MVC框架

    Spring MVC框架算是当下比较流行的Java开源框架.但实话实说,做了几年WEB项目,完全没有SpringMVC实战经验,乃至在某些交流场合下被同行严重鄙视“奥特曼”了.“心塞”的同时,只好默默 ...

  9. MVC框架模式技术实例(用到隐藏帧、json、仿Ajax、Dom4j、jstl、el等)

    前言: 刚刚学完了MVC,根据自己的感悟和理解写了一个小项目. 完全按照MVC模式,后面有一个MVC的理解示意图. 用MVC模式重新完成了联系人的管理系统: 用户需求: 多用户系统,提供用户注册.登录 ...

随机推荐

  1. maven搭建MVC项目具体步骤

    一.目标 在这篇文章中,我将要向您展示如何使用spring Frameworks 和 Maven build创建您的第一个J2ee 应用程序. 二.信息 Maven是一个Java项目的构建工具(或者自 ...

  2. 使用angular4和asp.net core 2 web api做个练习项目(一)

    这是一篇学习笔记. angular 5 正式版都快出了, 不过主要是性能升级. 我认为angular 4还是很适合企业的, 就像.net一样. 我用的是windows 10 安装工具: git for ...

  3. Input文本框属性及js

    <input id="txt_uname" maxlength="16" onblur="validata()" onkeyup=&q ...

  4. 2301: [HAOI2011]Problem b ( 分块+莫比乌斯反演+容斥)

    2301: [HAOI2011]Problem b Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 6015  Solved: 2741[Submit] ...

  5. Problem K

    Problem Description The local toy store sells small fingerpainting kits with between three and twelv ...

  6. JAVA 通过 Socket 实现 TCP 编程

    简介 TCP简介 TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议,由IETF的RFC 793定义.在简化的计算机 ...

  7. 机器翻译评测——BLEU改进后的NIST算法

    ◆版权声明:本文出自胖喵~的博客,转载必须注明出处. 转载请注明出处:http://www.cnblogs.com/by-dream/p/7765345.html 上一节介绍了BLEU算的缺陷.NIS ...

  8. 粗略整理的java面试题

    1.垃圾回收  是回收的空闲堆空间 只有在cpu空闲并且堆空间不足的情况下才回收 2.threadlocal  就是为线程的变量都提供了一个副本,每个线程运行都只是在更新这个副本. Threadloc ...

  9. Akka(36): Http:Client-side-Api,Client-Connections

    Akka-http的客户端Api应该是以HttpRequest操作为主轴的网上消息交换模式编程工具.我们知道:Akka-http是搭建在Akka-stream之上的.所以,Akka-http在客户端构 ...

  10. asp .net连接打开数据库初步

    1 #endregion59 WebDriver