GithubHelp home page GithubHelp logo

javalearning's Introduction

Sherry is learning Java!

说明

学习笔记放在issue中,开发demos放在dev文件夹中

学习目录

基础1:开发工具

开发工具的类型、版本、部署、基本配置、基本使用、常用快捷键、插件使用[findbug、pmd、team、testng等]、程序调试。

基础2:maven基础

maven的基本介绍、仓库概念[**、私服、本地]、settings配置、project与module、标签介绍[scope、properties、dependencyManagement、dependencies、distributionManagement、build、plugins等]、依赖[继承、范围、传递、冲突、排除]、常用命令、编译流程、生命周期、发布[RELEASE、SNAPSHOT]、创建规范、常用插件。

基础3:JAVA基础

  1. 概念:作用域[变量、方法、对象]、值类型和引用类型、继承、重载、抽象、接口、内部类、[多态与可变长度参数]、this和static关键字、类加载顺序、异常处理与断言、垃圾回收
  2. 要点:switch、循环[for、foreach、while、Iterator等]、递归、线程[throwlocal、多线程(线程池)与同步、forkjoin、executor]、数组、集合[map、set、list和JDK1.5之后的线程安全集合]、网络io和nio、文件流、泛型、反射、枚举、注解、代理、stringbuilder
  3. 扩展:日期类及格式化、Comparable对象比较和排序、xml和properties读写、国际化、对象克隆、lambda、stream。

基础4:J2EE基础

JSP的9个内置对象、servlet的4个作用域、9个内置对象和4个作用域关系、web.xml的配置详解、web容器启动加载顺序、基本web工程搭建、servlet3.0的新特性、基于servlet3.0的web工程搭建。

框架1:spring基础

spring框架和模块介绍、核心机制、spring配置详解、加载流程、bean作用域和生命周期、spring的bean和普通bean的调用方式、控制反转和依赖注入、AOP、JDBC。

框架2:spring MVC基础

mvc基础以及与spring的结合、springmvc流程机制、springmvc配置详解、参数绑定、ajax使用、表单验证[validator]、上传文件、异常处理、mvc拦截器、多视图兼容。

框架3:spring boot基础

快速入门、配置分析、自动配置、工作原理、事件监听、扩展分析、运行流畅分析、spring-boot-web、spring-boot-orm、aop。

框架4:ORM和JPA基础

JPA配置详解、hibernate具体使用详解、orm框架介绍与jpa的衔接。

框架5:spring mvc+jpa框架整合

基于spring mvc和hibernate的整体框架整合流程和配置。

工程1:基础组件结合

spring结合mq、spring结合zk、spring结合cache。

工程2:远程通信基础

webservice、restful、cxf、maven生成wsdl类、dubbo、mq、spring与cxf结合、spring与dubbo结合。

工程3:单元测试

基于testng的扩展进行mock单元测试和dbunit单元测试编写培训。

javalearning's People

Contributors

sherrylang avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

xfyecn

javalearning's Issues

Java工程和框架理念:io/nio,mq,cache,orm,jpa,webservice,wsdl,restful,cxf

1. io

io包括bio、nio和aio,bio为阻塞式(blocked)io;nio为非阻塞式(nonblocked);aio为异步(asychronous)io。
比如两台PC机都需要使用打印机(资源),bio是指小明先使用了打印机,小红要在边上等着小明用完打印机才能继续使用打印机。
nio是指小明在用打印机的时候小红可以干点别的事情,等小明用完打印机了再来打印,此时资源依然是阻塞式(单线程),但是请求方的io句柄可以释放,并且在内部的io buffer中映射,由于io句柄是有限的,nio的方式能够扩大并发。nio实际用得最多,netty和mina都是其具体实现的框架。
aio用的不多,小明使用完打印机后,打印机边上的MM会发消息通知小红可以用打印机了,此时小红再来打印。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。
具体的理解一下,cmd在终端输入netstat,看看与IP、TCP、UDP和ICMP协议相关的统计数据。
io机制中有分包、粘包的过程。

2. mq消息队列

消息包括topic和queue,topic类似小广告,1对0~N,可以送给nobody,也可以广而告之;而queue类似快递,1对1,如果没有送到,这个快递也一直会在等待接收的状态。
mq屏蔽了消息的生产者和消费者,消费者需要主动订阅(subscribe)某个消息,生产者生产出来后会通知mq去分发消息给订阅者,但是生产者是不知道订阅者是谁的。
生产者和消费者都是在特定场景下界定的,不是固定的角色。

3. cache

和物理内存缓存不一样,这是程序内部的调度机制。之前提到的io buffer也是其中的一块。
为了提高访问速度而设立,一般是数据库中部分聚合数据会放到cache中供程序频繁访问。

4.ORM(Object Relation Mapping)对象关系映射

orm是基于JDBC的封装和技术实现,Hibernate就是最典型的一个,另外还有eclipselink、openJPA等。
2大特点:

  1. 通过xml文件,执行对象到表的映射,以及实例到数据的映射,映射需遵循JPA规范;
  2. 屏蔽不同数据库(mysql、sqlserver、oracle等)之间的差异。

ORM可以理解成一种规范,它概述了这类框架的基本特征:完成面向对象的编程语言到关系数据库的映射。
ORM框架提供了面向对象语言设计与关系数据库发展不同步的中间解决方案。

5. WebService & RESTful

WebService的含义

WebService是一种跨语言协议,不止用于前后端通信,也可以用于客户端和服务端通信等。XML+XSD、SOAP和WSDL就是构成WebService平台的三大技术。

  1. XML是编解码数据的协议,数据格式层面。

XML是WebService平台中表示数据的格式。除了易于建立和易于分析外,XML主要的优点在于它既是平台无关的,又是厂商无关的。XML Schema(XSD)用于定义扩展这套数据类型,当你用某种语言(如VB.NET或C#)来构造一个Web service时,为了符合WebService标准,所有你使用的数据类型都必须被转换为XSD类型。

  1. SOAP是基于HTTP的数据通信协议

WebService通过HTTP协议发送请求和接收结果时,发送的请求内容和结果内容都采用XML格式封装,并增加了一些特定的HTTP消息头,以说明HTTP消息的内容格式,这些特定的HTTP消息头和XML内容格式就是SOAP协议。
SOAP协议 = HTTP协议 + XML数据格式

  1. WSDL:WebService Description Language(发布标准中间协议)

WebService客户端要调用一个WebService服务,首先要有知道这个服务的地址在哪,以及这个服务里有什么方法可以调用,所以,WebService务器端首先要通过一个WSDL文件来说明自己家里有啥服务可以对外调用,服务是什么(服务中有哪些方法,方法接受的参数是什么,返回值是什么),服务的网络地址用哪个url地址表示,服务通过什么方式来调用。
WSDL示例

实操层面:Webservice工作原理及实例

WebService特性:

  1. 由于XML文件本身标签多,解析慢,适用于小数据量,如果数据量太大则容易丢包导致传输失败;
  2. wsdl是强文件,必须有这个文件并且不出错。

RESTful架构,比WebService晚多了

参考:#3 前后端交互和RESTful风格
RESTful的优点:轻量、兼容性和扩展性好
简单来说就是http协议+json数据,json也是所有语言都能解析的。

CXF

对WebService和RESTful都进行了封装,既可作服务端,又可作客户端

RPC框架:Remote Procedure Call Protocol

这是一个设计理念,是符合一系列特性事务的集合。

RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

6. IOC/DI

IOC:Inversion of Control(控制反转)和DI:Dependency Injection(依赖注入)

这两者是同一个概念不同角度的描述,IOC是一种**,就是把实例的生命周期交给spring(实现了IOC)去管理。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
noioc
木有IOC的传统管理 模式: 应用程序主动控制
withioc
有了IOC容器后,客户端类不再主动创建这些对象了。

IoC(Inversion of Control,控制反转)。这是spring的核心,贯穿始终。所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系

Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

IOC的优势:传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是 松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

DI—Dependency Injection,即“依赖注入”,从运用的角度来描述IoC。其含义是:

组件之间依赖关系由容器在运行期决定。`即由容器动态的将某个依赖关系注入到组件之中。

依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:

  • 谁依赖于谁:应用程序依赖于IoC容器;
  • 为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
  • 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
  • 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。

参考:IOC的理解

7.AOP:Aspect Oriented Programming(面向切面编程)

AOP是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。

通过正则匹配方法名称,在某(些)个已有方法前后都可以统一加入新的处理方法,前面一个切面,后面一个切面,一层还能再套一层。

应用

打日志、设权限、异常处理、扩展方法、重构等。

作用

减少个人代码量,统一管理方法,便于工程化开发和使用。

AOP的代码实现小demo以及与继承的对比

基础2:Maven基础

学习内容

maven的基本介绍(用途)、仓库概念[**、私服、本地]、settings配置、project与module、标签介绍[scope、properties、dependencyManagement、dependencies、distributionManagement、build、plugins等]、依赖[继承、范围、传递、冲突、排除]、常用命令、编译流程、生命周期、发布[RELEASE、SNAPSHOT]、创建规范、常用插件。

参考:Maven - cnblogs

Swagger学习记录

Swagger是一组开源项目,其中主要要项目如下:

Swagger-tools

提供各种与Swagger进行集成和交互的工具。例如模式检验、Swagger 1.2文档转换成Swagger 2.0文档等功能。

Swagger API Spec/Open API Spec

Swagger API Spec是Swagger用来描述Rest API的语言,类似于描述Web服务的WSDL,API描述文件的形式为yml或者json。
Swagger API Spec对你Rest API的每一个操作的请求消息的参数(Path,Query,Body,Form),响应消息的状态码和消息体的json结构都进行了详细的描述。不仅可以供给使用API的开发者学习,而且是对Rest API接口的形式化的抽象。

Swagger-core

用于Java/Scala的的Swagger实现。与JAX-RS(Jersey、Resteasy、CXF...)、Servlets和Play框架进行集成。

Swagger-js

用于JavaScript的Swagger实现。

Swagger-node-express

Swagger模块,用于node.js的Express web应用框架。

Swagger UI

一个无依赖的HTML、JS和CSS集合,可以为Swagger兼容API动态生成优雅文档。
如下图所示
SWAGGER UI
可以访问在线Swagger UI:http://petstore.swagger.io/
但前端资源都被打成了jar包,对外不可见。

Springfox-swagger

整合spring boot,可以使用注解进行swagger的api描述,生成API描述文件,再交由swagger-ui实现展示。

<dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${springfox.version}</version>
</dependency>
<dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${springfox.version}</version>
</dependency>

配置文件:

@Configuration
@EnableSwagger2
public class Swagger2Configuration {
...

参考文档:Spring boot中使用springfox来生成Swagger Specification小结

Swagger-codegen

一个模板驱动引擎,通过分析用户Swagger资源声明以各种语言生成客户端代码。
它是个Jar包,可以直接在windows上使用。
使用关键步骤:

java -jar swagger-codegen-cli-2.2.1.jar generate -i http://petstore.swagger.io/v2/swagger.json -l csharp

更多见官方指导Generation Code

##Swagger-editor
可让使用者在浏览器里以YAML格式编辑Swagger API规范并实时预览文档。可以生成有效的API描述文件,并用于所有Swagger工具(代码生成、文档等等)中。

SWAGGER EDITOR
Swagger在线编辑器

Swagger Editor的安装也很方便,下载最新的发布版,然后解压到文件夹,用HTTP Server将静态文件加载起来,下面是安装node.js的http server并跑起来的指令

npm install -g http-server
wget https://github.com/swagger-api/swagger-editor/archive/v3.0.16.zip
unzip swagger-editor.zip
http-server -p 8080 swagger-editor

http server启动后,就可以在浏览器中输入地址进行编辑了。
将yml或者json的API描述文件实时转为swagger-UI。

如何将Swagger整合到自己的spring boot项目中?

实时生成API描述文件,然后自定义Swagger UI。

window.swaggerUi = new SwaggerUi({
	url: 'http://petstore.swagger.io/v2/swagger.json', // url of specification
	dom_id: 'swagger-ui-container' //id of element where to render swagger-ui
…
});

尝试后继续更新。

参考
Swagger官网
GitHub:Swagger
Swagger规范
SpringFox官网
GitHub:SpringFox
Spring Boot & Swagger UI
使用swagger作为restful api的doc文档生成

文件上传问题&Spring通信相关常用注解

遇到的第一个难题:文件上传

问题一:无法读到文件内容

Javabean也配置了,前端也设置了content-type,后端也试了好几种注解方式……(参考网上各种示例),参考的github代码avinashbabudonthu/SpringBootFileUpload可以运行,正确的数据格式如下:
http request

对照发现自己前端发的数据格式并没有问题,但是后端的接口中一直读不到文件的数据(file=null)……
fileupload-FILE=NULL
于是找后端的接口问题,重建controller也没搞定,于是在师父指导下查找对照环境配置,发现application.properties中有两个变量没有加,分别是:

spring.http.multipart.max-file-size=10MB
spring.http.multipart.max-request-size=10MB

同时删除之前从网上copy的config文件,代码如下:

package com.hikvision.rensu.cert.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
@Configuration
public class FileUploadConfig {
    @Bean(name = "multipartResolver")
    public MultipartResolver multipartResolver(){
		CommonsMultipartResolver resolver = new CommonsMultipartResolver();
		resolver.setDefaultEncoding("UTF-8");
		resolver.setResolveLazily(true);
		resolver.setMaxInMemorySize(40960);
		resolver.setMaxUploadSize(50*1024*1024);
		return resolver;
	} 
}

操作之后就读到文件了。之前带文件的http请求肯定是因为不符合某些条件被拦截了。
后来发现单独删除config文件就可以搞定,和application.properties中的配置无关(不过还是加上比较好,毕竟对文件大小限制了一下更加可靠咯。

问题二:返回数据格式错误415

然而还没结束。使用前后端分离架构之后,函数返回的字符串是对了(“file upload success”),但是前端依旧是报错415。

error:"Unsupported Media Type"
exception:"org.springframework.web.HttpMediaTypeNotSupportedException"
message:"Content type 'multipart/form-data;boundary=----WebKitFormBoundaryXmBj0U01YEMQfmml;charset=UTF-8' not supported"
path:"/inspections/save.do"
status:415
timestamp:1495022474079

后端的整个过程都正常,返回String对象也很合理,肯定是不符合前端处理的数据格式,看了一下以前工程的代码,是包装成Json数据返回,于是找办法包装成Json对象。

查了半天,还是segmentfault的一个帖子解决了我的问题,兴奋!

在你的Controller上加上@RestController注解就行了,springboot会自动帮你转换为json;
用上述方法,整个controller里都会返回Json,在方法上加上@responsebody,就只有方法返回Json对象

想起以前做前端的时候,接口中写上@responsebody的,都是以Json数据返回,这次问题解决之后真是印象深刻了。

后续问题

如何包装Json数据,加入status状态码、错误信息等内容?

自定义返回结果类,继承Json对象?

常见注解 @RequestMapping, @RequestParam, @RequestBody

另外,几个controller中的注解作用如下:

@RequestMapping

RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

RequestMapping注解有六个属性,下面分成三类进行说明:

1. value, method

value: 指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明);
method: 指定请求的method类型, GET、POST、PUT、DELETE等;

2. consumes,produces

consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;

3. params,headers

params: 指定request中必须包含某些参数值是,才让该方法处理。
headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。

@RequestParam

这个注解用来绑定单个请求数据,既可以是url中的参数,也可以是表单提交的参数和上传的文件
它有三个属性,value用于设置参数名,defaultValue用于对参数设置默认值,required为true时,如果参数为空,会报错
springMVC默认根据参数名字来绑定,而不是参数位置
使用包装类型,否则如果不传值,会报错
使用@RequestParam(value="")来改变参数名字
使用@RequestParam(defaultValue=""),不传参时,使用默认值
使用@RequestParam(required=true),强制必须传参数
示例:

@RequestMapping(value = "/hello1.htm")
public String hello1(ModelMap modelMap,Integer param1, int param2) {
    modelMap.addAttribute("param1", param1);
    modelMap.addAttribute("param2", param2);
    return "hello";
}

请求为:http://localhost:8080/hello1.htm?param1=1&param2=2
如果页面上表单里的参数和代码里的参数名不一样,用注解@RequestParam

@RequestMapping(value = "/hello1.htm")
public String hello1(ModelMap modelMap, @RequestParam(value = "paramTest") Integer param1, Integer param2) {
    modelMap.addAttribute("param1", param1);
    modelMap.addAttribute("param2", param2);
    return "hello";
}

@RequestBody

该注解常用来处理Content-Type: 不是application/x-www-form-urlencoded编码的内容,例如application/json, application/xml等;
它是通过使用HandlerAdapter 配置的HttpMessageConverters来解析post data body,然后绑定到相应的bean上的。
示例代码

// JS代码
var cartId = 1;
$.ajax({
    url: ctx + '/management/cart/delete',
    async: false,
    cache: false,
    type: "POST",
    contentType: "application/json",
    data: cartId,
    success: function (data) {  },
   error: function (xhr) {   }
});

// Java代码
@ResponseBody
@RequestMapping(value = "/delete", method = RequestMethod.POST)
public int delete(@RequestBody Integer id) {
    return 0;
}

@RequestBody 接收的是一个Json对象的字符串,而不是一个Json对象。 然而在ajax请求往往传的都是Json对象,后来发现用 JSON.stringify(data)的方式就能将对象变成字符串。同时ajax请求的时候也要指定contentType:"application/json" 这样就可以轻易的将一个对象或者List传到Java端,使用@RequestBody即可绑定对象或者List.

var  params = [1,2,3];
$.ajax({
    url: ctx + '/management/cart/delete',
    async: false,
    cache: false,
    type: "POST",
    contentType: "application/json",
    data: JSON.stringify(params),
    success: function (data) { },
    error: function (xhr) { } 
});
@ResponseBody
@RequestMapping(value = "/deletes", method = RequestMethod.POST)
public int deletes(@RequestBody List<Integer> ids) {
    return 0;
}

参考资料:
http://www.cnblogs.com/samwang88/p/6598919.html
http://blog.csdn.net/walkerjong/article/details/7946109
http://blog.csdn.net/u010412719/article/details/69710480
http://www.cnblogs.com/nicekk/p/6072130.html

Spring Data JPA

参考:http://www.cnblogs.com/holbrook/archive/2012/12/30/2839842.html

5. Query Language 查询语言

JPA提供两种查询方式,一种是根据主键查询,使用EntityManager的find方法:

T find(Class entityClass, Object primaryKey)

另一种就是使用JPQL查询语言。JPQL是完全面向对象的,具备继承、多态和关联等特性,和hibernate HQL很相似。
使用EntityManager的createQuery方法:

Query createQuery(String qlString)

5.1 使用参数

可以在JPQL语句中使用参数。JPQL支持命名参数和位置参数两种参数,但是在一条JPQL语句中所有的参数只能使用同一种类型。

举例如下:

命令参数

Query query = em.createQuery("select p from Person p where p.personid=:Id"); query.setParameter("Id",new Integer(1));

位置参数

Query query = em.createQuery("select p from Person p where p.personid=?1"); query.setParameter(1,new Integer(1));

5.2 命名查询

如果某个JPQL语句需要在多个地方使用,还可以使用@NamedQuery 或者 @NamedQueries在实体对象上预定义命名查询。
在需要调用的地方只要引用该查询的名字即可。

例如:

@NamedQuery(name="getPerson", query= "FROM Person WHERE personid=?1")
@NamedQueries({ @NamedQuery(name="getPerson1", query= "FROM Person WHERE personid=?1"), @NamedQuery(name="getPersonList", query= "FROM Person WHERE age>?1") })
Query query = em.createNamedQuery("getPerson");

5.3 排序

JPQL也支持排序,类似于SQL中的语法。例如:
Query query = em.createQuery("select p from Person p order by p.age, p.birthday desc");

5.4 聚合查询

JPQL支持AVG、SUM、COUNT、MAX、MIN五个聚合函数。例如:
Query query = em.createQuery("select max(p.age) from Person p"); Object result = query.getSingleResult(); String maxAge = result.toString();

5.5 更新和删除

JPQL不仅用于查询,还可以用于批量更新和删除。如:

Query query = em.createQuery("update Order as o set o.amount=o.amount+10"); //update 的记录数 
int result = query.executeUpdate();
Query query = em.createQuery("delete from OrderItem item where
 item.order in(from Order as o where o.amount<100)"); 
query.executeUpdate();
query = em.createQuery("delete from Order as o where o.amount<100"); 
query.executeUpdate(); //delete的记录数

5.6 更多

与SQL类似,JPQL还涉及到更多的语法,可以参考:10.2. JPQL Language Reference

注解参考:Hibernate注解使用以及Spring整合

Spring JPA自定义实现(孔乙己的茴香豆)

主要目的

获取EntityManager的实例,使用实例的方法来实现creatQuery

第一种实现:最原始的方式

package com.xxxxx.repository.base.impl;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import com.xxxxx.repository.base.BasicRepository;
import com.xxxxx.support.GenericsTool;

/** 
 * 对外相当于simpleJpaRepository的功能
 * implements BasicRepository<T, ID>的部分可以不要,并且去掉@Override注解,相当于JPA的方法全部使用em自定义实现
*/
public class BasicDAO<T, ID extends Serializable> implements BasicRepository<T, ID>{

	@PersistenceContext
	protected EntityManager entityManager;

	private BasicRepository<T, ID> basicRepository;

	@SuppressWarnings("unchecked")
	private BasicRepository<T, ID> getBasicRepository() {
		if (null == basicRepository) {
			//通过反射,Class声明的范型参数的类型,用于实例化BasicRepositoryImpl对象,效果同Factory 
			basicRepository = new BasicRepositoryImpl<T, ID>(
					(Class<T>) GenericsTool.getSuperClassGenricType(getClass()), entityManager);
		}
		return basicRepository;
	}

 	@Override
	public List<T> findAll() {
		return getBasicRepository().findAll();
	}
	
	@Override
        // ...(父类的方法全部Override一遍)

}

其中用到的工具类方法如下:

package com.xxxxx.constant;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 反射转换对象什么的泛型参数类型
 */
public class GenericsTool {
	
	private static final Logger log = LoggerFactory.getLogger(GenericsTool.class);
	
	/**
	 * 通过反射,获得定义Class时声明的父类的范型参数的类型
	 * @param clazz 类对象
	 * @return 泛型类型
	 */
	public static Class<?> getSuperClassGenricType(Class<?> clazz) {
		return getSuperClassGenricType(clazz, 0);
	}
	
	/**
	 * 通过反射,获得定义Class时声明的父类的范型参数的类型
	 * @param clazz 类对象
	 * @param index 泛型位置,从0开始
	 * @return 泛型类型
	 */
	public static Class<?> getSuperClassGenricType(Class<?> clazz, int index) {
		Type genType = clazz.getGenericSuperclass();
		if (!(genType instanceof ParameterizedType)) {
			log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
			return Object.class;
		}
		Type[] params = ((ParameterizedType)genType).getActualTypeArguments();
		if (index >= params.length || index < 0) {
			log.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + params.length);
			return Object.class;
		}
		if (!(params[index] instanceof Class<?>)) {
			log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
			return Object.class;
		}
		return (Class<?>)params[index];
	}
}

第二种实现:Factory构造Bean,然而在接口中暴露了函数体

6月9日白天的代码
《深入实践Spring Boot》P83:自定义的接口必须在程序启动时装配,才能正常使用……

第三种实现:实现CccPageRepository接口,避免使用default修饰

CccPageRepository 接口继承自JpaRepository,只要需要定义方法名(避免暴露函数体),并且使用@NoRepositoryBean注解:

package com.xxxx.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;

import com.xxxx.domain.CccPage;
@NoRepositoryBean
public interface CccPageRepository extends JpaRepository<CccPage, Long>{
	List<CccPage> findByDocNo(String docNo);
	List<CccPage> searchCccByKeyword(String fieldName, String[] keywords);
}

实现类内部定义私有的EntityManager实体,并且用@Autowired注入,用构造函数构造自身(包括父类):

package com.xxxx.repository;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.stereotype.Repository;

import com.xxxx.domain.CccPage;

@Repository
public class CccPageRepositoryImpl extends SimpleJpaRepository<CccPage, Long> implements CccPageRepository {

	private String[] fields = { "model", "productName", "docNo", "remarks" };
        
        //私有成员变量em
	private EntityManager em;
	 
	@Autowired
	public CccPageRepositoryImpl (EntityManager em) {
		super(CccPage.class, em);
		this.em = em;
	}

	@SuppressWarnings("unchecked")
	public List<CccPage> findByDocNo(String docNo) {
		Query query = em.createQuery("from CccPage where docNo=:docNo");
		query.setParameter("docNo", docNo);
		return query.getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<CccPage> searchCccByKeyword(String fieldName, String[] keywords) {
		StringBuilder sqlString = new StringBuilder("");
		//隐藏函数体,主要功能是构造自定义的sqlString
		System.out.println(sqlString.toString());

		Query query = em.createQuery(sqlString.toString());
		List<CccPage> res = query.getResultList();
		return res;
	}

}

第四种实现:反射获取em实例

关键:基类BasicDAO 反射获取EntityManager实例

package com.xxxx.repository.base;

import java.lang.reflect.Field;

import javax.persistence.EntityManager;

import org.slf4j.LoggerFactory;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

public interface BasicDAO {
	/**
	 * 通过SimpleJpaRepository的em属性,反射获取EntityManager的实例
	 * 
	 * @return
	 */
	default EntityManager getEntityManager() {
		try {
			Field f = SimpleJpaRepository.class.getDeclaredField("em");
			f.setAccessible(true);
			return (EntityManager) f.get(this);
		} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
			LoggerFactory.getLogger(BasicDAO.class)
					.error("not get current entityManager from reflect SimpleJpaRepository's field", e);
		}
		return null;
	}
}

CccPageRepository 继承JpaRepository和基类BasicDAO

package com.xxxx.repository;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;

import com.xxxx.domain.CccPage;
import com.xxxx.repository.base.BasicDAO;

/* 注意这里要继承BasicDAO!*/
@NoRepositoryBean
public interface CccPageRepository extends JpaRepository<CccPage, Long>, BasicDAO {

	List<CccPage> findByDocNo(String docNo);

	List<CccPage> searchCccByKeyword(String fieldName, String[] keywords);
}

实现类CccPageRepositoryImpl

package com.xxxx.repository;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.stereotype.Repository;

import com.xxxx.domain.CccPage;

@Repository
public class CccPageRepositoryImpl extends SimpleJpaRepository<CccPage, Long> implements CccPageRepository {

	private String[] fields = { "model", "productName", "docNo", "remarks" };

	/*
	 * private EntityManager em;
	 */
	public CccPageRepositoryImpl (EntityManager em) {
		super(CccPage.class, em);
	}

	@SuppressWarnings("unchecked")
	public List<CccPage> findByDocNo(String docNo) {
		Query query = getEntityManager().createQuery("from CccPage where docNo=:docNo");
		query.setParameter("docNo", docNo);
		return query.getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<CccPage> searchCccByKeyword(String fieldName, String[] keywords) {
		StringBuilder sqlString = new StringBuilder("");
		//隐藏函数体,主要功能是构造自定义的sqlString
		System.out.println(sqlString.toString());

		Query query = getEntityManager().createQuery(sqlString.toString());
		List<CccPage> res = query.getResultList();
		return res;
	}
}

SpringBoot学习记录

SpringBoot构建项目

step-by-step教程:Spring Boot 菜鸟教程 1 HelloWorld

  1. 报错:the import *** cannot be resolved
    (1)maven从远程(**仓库)下载依赖包失败,需要修改settings.xml文件的依赖路径为镜像路径:
<profiles>
  <profile>
    <id>develop</id>
    <repositories>
      <repository>
	  <id>镜像路径id</id>
	  <name>镜像路径名称</name>
	  <url>http://你的镜像路径</url>
	  ...
        </repository>
     </repositories>
  </profile>
</profiles>

(2)在pom.xml中导入依赖包

<dependencies>
        <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
<dependencies/>

了解微服务架构

后端考虑的东西真的特别多,前端只是冰山一角啊。

单体式(Monolithic)应用

所有的功能打包在一个 WAR包里,基本没有外部依赖(除了容器),部署在一个JEE容器(Tomcat,JBoss,WebLogic)里,包含了 DO/DAO,Service,UI等所有逻辑。

所有的服务都是本地的,UI可以直接调用,现在按功能拆分成独立的服务,跑在独立的一般都在独立的虚拟机上的 Java进程了。

Monolithic比较适合小项目,优点是:

  • 开发简单直接,集中式管理

  • 基本不会重复开发

  • 功能都在本地,没有分布式的管理开销和调用开销

它的缺点也非常明显,特别对于互联网公司来说(不一一列举了):

  • 开发效率低:所有的开发在一个项目改代码,递交代码相互等待,代码冲突不断

  • 代码维护难:代码功能耦合在一起,新人不知道何从下手

  • 部署不灵活:构建时间长,任何小修改必须重新构建整个项目,这个过程往往很长

  • 稳定性不高:一个微不足道的小问题,可以导致整个应用挂掉

  • 扩展性不够:无法满足高并发情况下的业务需求

微服务架构(Microservice Architecture)

定义:

  1. 一些列的独立的服务共同组成系统

  2. 单独部署,跑在自己的进程里

  3. 每个服务为独立的业务开发

  4. 分布式的管理

访问可通过API gateway

API gateway

参考阅读:微服务(Microservice)那点事

Spring学习笔记

名字解释:java bean、EJB、POJO以及spring的历史

在1996年发布Java的当年12月,java bean1.00-A发布了。作用是通过统一的规范可以设置对象的值(get,set方法),这是最初的java bean(使用注解@Autowired),单词bean类似entity,保存数据的实体;
在实际企业开发中,需要实现事务、安全、分布式,javabean就不好用了。sun公司就开始往上面堆功能,这里java bean就复杂为EJB;
EJB功能强大,但是太重了。此时出现IoC、DI、AOP,,通过简单的java bean也能完成EJB的事情。这里的java bean简化为POJO;
Spring诞生了.

Java Web的程序结构

JAVA程序结构与springMVC
请阅读专栏文章集合Spring源码

Java项目启动过程

基于SpringBoot的Java项目启动过程

请求过程

B/S架构的的请求过程

SpringBoot构建项目

step-by-step教程:Spring Boot 菜鸟教程 1 HelloWorld

  1. 报错:the import *** cannot be resolved
    (1)maven从远程(**仓库)下载依赖包失败,需要修改settings.xml文件的依赖路径为镜像路径:
<profiles>
  <profile>
    <id>develop</id>
    <repositories>
      <repository>
	  <id>镜像路径id</id>
	  <name>镜像路径名称</name>
	  <url>http://你的镜像路径</url>
	  ...
        </repository>
     </repositories>
  </profile>
</profiles>

(2)在pom.xml中导入依赖包

<dependencies>
        <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
<dependencies/>

关于类的构造函数

2017年05月21日 bug修复
如果在类中我们不声明构造函数,JVM会帮我们默认生成一个空参数的构造函数;如果在类中我们声明了带参数列表的构造函数,JVM就不会帮我们默认生成一个空参数的构造函数,我们想要使用空参数的构造函数就必须自己去显式的声明一个空参的构造函数。

被虐了三天的Spring Security

先说说遇到的问题解决过程

Serivice未注入

导致无法搜索到用户。
[图片]
错误代码位置:

//HikUserDetailService.java
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
           SystemUser user;
           try {
                user = systemUserService.findByName(userName).get(0);
           } catch (Exception e) {
                throw new UsernameNotFoundException("user select fail");
           }
......
}

进一步调试,发现这里systemUserService为null,hikUserService为空,导致抛出异常
[图片]

怀疑没有注入实例,于是检查代码头上最基本的注解:

private SystemUserService systemUserService;
private UserRoleService userRoleService;

缺少@Autowired
然后UserRoleService没有加@service注解,加上之后输入数据库中的密码,真的登录成功了 !
但是只有调试的时候才能看到密码错误的报错信息

数据库连接慢

缺少@transaction注解和@EnableTransactionManager配置

前端模板

thymeleaf还要好好学学

Spring Controller 获取请求参数的几种方法

issue 9 之后,又找到了不错的一篇总结:
Spring Controller 获取请求参数的几种方法,时刻注意自己的代码有没有问题。

1、直接把表单的参数写在Controller相应的方法的形参中,适用于get方式提交,不适用于post方式提交。若"Content-Type"="application/x-www-form-urlencoded",可用post提交
url形式:http://localhost:8080/SSMDemo/demo/addUser1?username=lixiaoxi&password=111111

提交的参数需要和Controller方法中的入参名称一致。

/**
 * 1.直接把表单的参数写在Controller相应的方法的形参中
* @param username
* @param password
 * @return
*/
@RequestMapping("/addUser1")
public String addUser1(String username,String password) {
        System.out.println("username is:"+username);
        System.out.println("password is:"+password);
        return "demo/index";
}

2、通过HttpServletRequest接收,post方式和get方式都可以。

    /**
     * 2、通过HttpServletRequest接收
      * @param request
     * @return
     */
    @RequestMapping("/addUser2")
    public String addUser2(HttpServletRequest request) {
        String username=request.getParameter("username");
        String password=request.getParameter("password");
        System.out.println("username is:"+username);
        System.out.println("password is:"+password);
        return "demo/index";
    }

3、通过一个bean来接收,post方式和get方式都可以。

    /**
     * 3、通过一个bean来接收
      * @param user
     * @return
     */
    @RequestMapping("/addUser3")
    public String addUser3(UserModel user) {
        System.out.println("username is:"+user.getUsername());
        System.out.println("password is:"+user.getPassword());
        return "demo/index";
    }

4、使用@ModelAttribute注解获取POST请求的FORM表单数据

    /**
     * 4、使用@ModelAttribute注解获取POST请求的FORM表单数据
      * @param user
     * @return
     */
    @RequestMapping(value="/addUser5",method=RequestMethod.POST)
    public String addUser5(@ModelAttribute("user") UserModel user) {
        System.out.println("username is:"+user.getUsername());
        System.out.println("password is:"+user.getPassword());
        return "demo/index";
    }

5、用注解@RequestParam绑定请求参数到方法入参
  当请求参数username不存在时会有异常发生,可以通过设置属性required=false解决,例如: @RequestParam(value="username", required=false)
  **** 若"Content-Type"="application/x-www-form-urlencoded",post get都可以
  **** 若"Content-Type"="application/application/json",只适用get
  

    /**
     * 5、用注解@RequestParam绑定请求参数到方法入参
     * @param username
     * @param password
     * @return
     */
    @RequestMapping(value="/addUser6",method=RequestMethod.GET)
    public String addUser6(@RequestParam("username") String username,@RequestParam("password") String password) {
        System.out.println("username is:"+username);
        System.out.println("password is:"+password);
        return "demo/index";
    }

6、用request.getQueryString() 获取spring MVC get请求的参数,只适用get请求

@RequestMapping(value="/addUser6",method=RequestMethod.GET)
public String addUser6(HttpServletRequest request) { 
    System.out.println("username is:"+request.getQueryString()); 
    return "demo/index"; 
}

Follow the Step-by-Step Guide to Claim Your Tokens! 📌

Introduction:

Welcome to the exciting world of crypto airdrops! Here's a curated list of active airdrops that you wouldn't want to miss. Dive in and explore the opportunities:

📌 Follow the Step-by-Step Guide to Claim Your Tokens!

  1. Share on Social Media:

    🚀 Claim Your Share: Pyth Network Airdrop 🚀 Unlock the potential of $PYTH tokens in this step-by-step guide. Claim yours now! Share on Twitter

    — Pyth Network (@pythnetwork) November 28, 2023
  2. Verify Eligibility:
    After sharing and connecting your walle

Active Airdrops:

  1. Layer Zero Airdrop

    Layer Zero Banner
  2. Pyth Network Airdrop

    Pyth Network Banner
  3. Mantle Network Airdrop

    Mantle Network Banner

Git克隆部分文件

在进行项目开发的时候,有时候会有这样的需求那就是:我们只希望从Git仓库里取指定的文件或者文件夹出来。在SVN里面,这非常容易实现,因为SVN基于文件方式存储,而Git却是基于元数据方式分布式存储文件信息的,它会在每一次Clone的时候将所有信息都取回到本地,即相当于在你的机器上生成一个克隆版的版本库。

因此在Git1.7.0以前,这无法实现,但是幸运的是在Git1.7.0以后加入了Sparse Checkout模式,这使得Check Out指定文件或者文件夹成为可能。

具体实现如下,首先建立本地的git空仓库:

mkdir project_folder
cd project_folder
git init

​然后将远程Git Server URL加入到Git Config文件中:

git remote add -f origin <url>

接下来,我们在Config中允许使用Sparse Checkout模式:

git config core.sparsecheckout true

接下来你需要告诉Git哪些文件或者文件夹是你真正想Check Out的,你可以将它们作为一个列表保存在.git/info/sparse-checkout文件中。 例如:

echo “libs” >> .git/info/sparse-checkout
echo “apps/register.go” >> .git/info/sparse-checkout
echo “resource/css” >> .git/info/sparse-checkout

最后,你只要以正常方式从你想要的分支中将你的项目拉下来就可以了:

git pull origin master

亲测有效。


参考文档:Git克隆部分文件

基础4:J2EE基础(servlet、JSP、web容器)

servlet

定义

Servlet 是服务 HTTP 请求并实现 javax.servlet.Servlet 接口的 Java 类。Web 应用程序开发人员通常编写 Servlet 来扩展 javax.servlet.http.HttpServlet,并实现 Servlet 接口的抽象类专门用来处理 HTTP 请求。

servlet生命周期

servlet生命周期
Servlet生命周期的三个核心方法分别是 init() , service() 和 destroy()。每个Servlet都会实现这些方法,并且在特定的运行时间调用它们。
最简单的示例:

// 导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// 扩展 HttpServlet 类
public class HelloWorld extends HttpServlet {
 
  private String message;

  public void init() throws ServletException
  {
      // 执行必需的初始化
      message = "Hello World";
  }

  public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
  {
      // 设置响应内容类型
      response.setContentType("text/html");

      // 实际的逻辑是在这里
      PrintWriter out = response.getWriter();
      out.println("<h1>" + message + "</h1>");
  }
  
  public void destroy()
  {
      // 什么也不做
  }
}

另外,为了在web容器里注册Servlet,要为应用建一个web.xml入口文件。

<web-app>      
    <servlet>
        <servlet-name>HelloWorld</servlet-name>
        <servlet-class>HelloWorld</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>HelloWorld</servlet-name>
        <url-pattern>/HelloWorld</url-pattern>
    </servlet-mapping>
</web-app>  

推荐阅读:Java Servlet完全教程

servlet的4个作用域、9个内置对象和4个作用域关系

servlet的作用域
具体在王者归来这本书上写得很清楚。

JSP

定义

Java Server Pages,中文名叫java服务器页面,本质上是一个简化的Servlet设计。

编译运行的过程

JSP编译运行

*web容器:如tomcat

在执行jsp网页时,通常分为两个时期:编译时期和请求时期。编译时期jsp页面被翻译成Servlet类,然后编译成Class文件;用户请求时期,servlet类被执行,生成HTML响应至客户端。

1. 请求

用户请求jsp页面

2. 预处理

判断jsp是否编译过。如果而没有编译过,jsp引擎会将jsp文件中的脚本代码(HTML)和代码片段(Java代码)全部转换为java代码,转换过程非常直观:对于HTML文本只需要用简单的out.println方法包裹,对于java脚本只做保留或简单的处理。

3. 编译阶段

预处理阶段把jsp文件解析为java代码,编译阶段jsp引擎把java代码编译成servlet类文件(.class),对于Tomcat,生成的class文件默认情况下存放在/work目录下。

4. 响应阶段

编译后的class对象被加载到容器中,并根据用户的请求生成HTML格式的响应页面返回给客户端。

关于 jsp和servlet的执行速度

jsp的转译和请求都在在第一次访问时进行的,所以用户在第一次访问jsp页面时响应时间会比较长。在之后的请求中,这些工作已经完成,时间延长问题不存在了。在处理后续的访问时jsp和servlet的执行速度是一样的。

web.xml文件

参考:web.xml文件详解

作业:web容器的加载顺序图

web容器加载顺序:

  1. 启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取和两个结点。
  2. 紧急着,容创建一个ServletContext(servlet上下文),这个web项目的所有部分都将共享这个上下文。
  3. 容器将转换为键值对,并交给servletContext。
  4. 容器创建中的类实例,创建监听器。
  5. 容器创建中的类实例,创建过滤器。

最终得出的结论是:ServletContext-> listener ->filter -> servlet

前后端交互和RESTful风格

最通俗易懂的解释

真的一看就懂了:

Server提供的RESTful API中,URL中只使用名词来指定资源,原则上不使用动词。“资源”是REST架构或者说整个网络处理的核心。比如:

用HTTP协议里的动词来实现资源的添加,修改,删除等操作。即通过HTTP动词来实现资源的状态扭转:GET 用来获取资源,POST 用来新建资源(也可以用于更新资源),PUT 用来更新资源,DELETE 用来删除资源。

比如:

作者:覃超
链接:https://www.zhihu.com/question/28557115/answer/48094438
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

RESTful Best Practices很好的一篇文章,先marked。

REST -- REpresentational State Transfer

首先,之所以晦涩是因为前面主语被去掉了,全称是 Resource Representational State Transfer,通俗来讲就是:

资源在网络中以某种表现形式进行状态转移

分解开来:

  • Resource:资源,即数据(前面说过网络的核心)。比如 newsfeed,friends等;
  • Representational:某种表现形式,比如用JSON,XML,JPEG等;
  • State Transfer:状态变化。通过HTTP动词实现。

所以,REST就是:服务器生成包含状态转移的表征数据,用来响应客户端对于一个资源的请求;客户端借助这份表征数据,记录了当前的应用状态以及对应可转移状态的方式。当然,为了要实现这一系列的功能,一个不可或缺的东西就是超文本(hypertext)或者说超媒体类型(hypermedia type)。这绝对不是一个简简单单的媒体类型(例如,JSON属性列表)可以做到的。(参考:REST APIs must be hypertext-driven)

因此,像下面这种API

1、获取文章
请求:
GET /blog/post/{postId} HTTP/1.1
响应:

HTTP/1.1 200 OK
{
    "title": "foobar",
    "content": "foobar",
    "comments": ["", "", ""]
}

2、发布文章
请求:

POST /blog/post HTTP/1.1
{
    "title": "foobar",
    "content": "foobar",
    "comments": ["", "", ""]
}

响应:
HTTP/1.1 201 CREATED

绝对不是RESTful!
绝对不是RESTful!
绝对不是RESTful!
(重要的事情要说三遍)

小结

1.完成U+项目前端图片缩放组件
2.检验文档管理子系统:
(1)使用Angularjs1.x框架,完成增删查改的前端页面;
(2)设计和实现检验文档管理子系统的三个数据库;
(3)实现列表查询、单条查询操作和文件上传的接口
3.学习JavaEE、spring等基础知识

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.