users = new ArrayList<>();
32 | User sam = new User(1, "sam", 22, new Date());
33 | User tom = new User(2, "tom", 23, new Date());
34 | users.add(sam);
35 | users.add(tom);
36 | return users;
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/blade-mongo/src/main/java/com/blade/demo/mongo/MongoConfig.java:
--------------------------------------------------------------------------------
1 | package com.blade.demo.mongo;
2 |
3 | import com.hellokaton.blade.Blade;
4 | import com.hellokaton.blade.ioc.annotation.Bean;
5 | import com.hellokaton.blade.loader.BladeLoader;
6 | import com.mongodb.MongoClient;
7 | import com.mongodb.client.MongoDatabase;
8 |
9 | /**
10 | * @author biezhi
11 | * @date 2018/4/27
12 | */
13 | @Bean
14 | public class MongoConfig implements BladeLoader {
15 |
16 | private static MongoDatabase mongoDatabase;
17 |
18 | public static MongoDatabase getMongoDatabase() {
19 | return mongoDatabase;
20 | }
21 |
22 | @Override
23 | public void load(Blade blade) {
24 | MongoClient mongoClient = new MongoClient("localhost");
25 | // MongoClient mongoClient = new MongoClient("localhost", 27017);
26 | // MongoClientURI connectionString = new MongoClientURI("mongodb://localhost:27017");
27 | // MongoClient mongoClient = new MongoClient(connectionString);
28 |
29 | mongoDatabase = mongoClient.getDatabase("blade_demo");
30 | System.out.println(mongoDatabase.getName());
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/blade-upload/src/main/java/com/blade/demo/upload/UploadController.java:
--------------------------------------------------------------------------------
1 | package com.blade.demo.upload;
2 |
3 | import com.hellokaton.blade.annotation.Path;
4 | import com.hellokaton.blade.annotation.request.Multipart;
5 | import com.hellokaton.blade.annotation.route.GET;
6 | import com.hellokaton.blade.annotation.route.POST;
7 | import com.hellokaton.blade.kit.BladeKit;
8 | import com.hellokaton.blade.mvc.multipart.FileItem;
9 | import com.hellokaton.blade.mvc.ui.RestResponse;
10 |
11 | import java.io.IOException;
12 | import java.nio.file.Paths;
13 |
14 | /**
15 | * 上传文件控制器
16 | *
17 | * @author biezhi
18 | * @date 2017/10/1
19 | */
20 | @Path
21 | public class UploadController {
22 |
23 | @GET
24 | public String index() {
25 | return "upload.html";
26 | }
27 |
28 | @POST("upload")
29 | public RestResponse> doUpload(@Multipart FileItem fileItem) throws IOException {
30 | if (null != fileItem) {
31 | fileItem.moveTo(Paths.get(BladeKit.getCurrentClassPath() + "/upload/" + fileItem.getFileName()));
32 | return RestResponse.ok();
33 | }
34 | return RestResponse.fail("没有文件上传");
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/blade-anima/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | blade-demos
7 | com.hellokaton
8 | 0.0.1
9 |
10 | 4.0.0
11 |
12 | blade-anima
13 |
14 |
15 |
16 |
17 | com.hellokaton
18 | anima
19 | 0.3.1
20 |
21 |
22 |
23 | com.alibaba
24 | druid
25 | 1.2.9
26 |
27 |
28 |
29 | mysql
30 | mysql-connector-java
31 | 5.1.47
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/blade-anima/src/main/java/com/bladejava/anima/IndexController.java:
--------------------------------------------------------------------------------
1 | package com.bladejava.anima;
2 |
3 | import com.hellokaton.blade.annotation.Path;
4 | import com.hellokaton.blade.annotation.request.Body;
5 | import com.hellokaton.blade.annotation.request.PathParam;
6 | import com.hellokaton.blade.annotation.route.DELETE;
7 | import com.hellokaton.blade.annotation.route.GET;
8 | import com.hellokaton.blade.annotation.route.POST;
9 | import com.hellokaton.blade.mvc.ui.ResponseType;
10 | import com.hellokaton.blade.mvc.ui.RestResponse;
11 |
12 | import static com.hellokaton.anima.Anima.deleteById;
13 | import static com.hellokaton.anima.Anima.select;
14 |
15 | @Path(responseType = ResponseType.JSON)
16 | public class IndexController {
17 |
18 | @GET("users")
19 | public RestResponse users() {
20 | return RestResponse.ok(select().from(User.class).all());
21 | }
22 |
23 | @POST("users")
24 | public RestResponse saveUser(@Body User user) {
25 | return RestResponse.ok(user.save().asInt());
26 | }
27 |
28 | @DELETE("user/:uid")
29 | public RestResponse deleteUser(@PathParam Integer uid) {
30 | return RestResponse.ok(deleteById(User.class, uid));
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/blade-upload/src/main/resources/templates/upload.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
10 |
11 |
14 |
18 |
19 |
20 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/blade-websocket/src/main/java/com/bladejava/demo/ws/WebSocketApplication.java:
--------------------------------------------------------------------------------
1 | package com.bladejava.demo.ws;
2 |
3 | import com.hellokaton.blade.Blade;
4 |
5 | /**
6 | * @author biezhi
7 | * @date 2018/8/16
8 | */
9 | public class WebSocketApplication {
10 |
11 | public static void main(String[] args) {
12 | Blade.create()
13 | .get("/", ctx -> ctx.render("index.html"))
14 | // .webSocket("/chat", new WebSocketHandler() {
15 | // @Override
16 | // public void onConnect(WebSocketContext ctx) {
17 | // System.out.println("有新连接: " + ctx);
18 | // }
19 | //
20 | // @Override
21 | // public void onText(WebSocketContext ctx) {
22 | // System.out.println("有新消息: " + ctx.getReqText());
23 | // ctx.message("服务器返回:" + ctx.getReqText());
24 | // }
25 | //
26 | // @Override
27 | // public void onDisConnect(WebSocketContext ctx) {
28 | // System.out.println("有断开连接: " + ctx);
29 | // }
30 | // })
31 | .start(WebSocketApplication.class, args);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/blade-anima/README.md:
--------------------------------------------------------------------------------
1 | # blade-anima
2 |
3 | 1. 导入数据库结构和数据 `resources/schema.sql`
4 | 2. 启动 `DBApplication.java`
5 |
6 | ## 测试
7 |
8 | 获取所有用户
9 |
10 | ```shell
11 | curl -i http://127.0.0.1:9000/users
12 |
13 | HTTP/1.1 200 OK
14 | Content-Length: 391
15 | Date: Tue, 27 Nov 2018 16:30:29 GMT
16 | X-Powered-By: blade-2.0.12.BETA
17 | Set-Cookie: SESSION=thiim3pjq4hvgpmf64ilj4hiei; Path=/; HTTPOnly
18 | Content-Type: application/json; charset=UTF-8
19 | Connection: keep-alive
20 |
21 | {"payload":[{"id":1,"username":"jack","password":"aaa","realName":"杰克","age":32},{"id":2,"username":"rose","password":"999","realName":"螺丝","age":29},{"id":3,"username":"biezhi","password":"123556","realName":"魔王不造反","age":19},{"id":4,"username":"codesofun","password":"123556","realName":"代码真香","age":20}],"success":true,"msg":null,"code":0,"timestamp":1543307430}
22 | ```
23 |
24 | 添加一个用户
25 |
26 | ```shell
27 | curl -X POST http://127.0.0.1:9000/users \
28 | -H 'Content-Type: application/json' \
29 | -d '{"username":"test","password":"123456","realName":"测试数据","age": 10}'
30 |
31 | {"payload":5,"success":true,"msg":null,"code":0,"timestamp":1543307570}
32 | ```
33 |
34 | 删除一个用户
35 |
36 | ```shell
37 | curl -X DELETE http://127.0.0.1:9000/user/5
38 |
39 | {"payload":1,"success":true,"msg":null,"code":0,"timestamp":1543307647}
40 | ```
--------------------------------------------------------------------------------
/blade-package/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | customAssembly
7 |
8 |
9 | dir
10 |
11 |
12 | false
13 |
14 |
15 |
16 | src/main/resources/
17 | /resources
18 |
19 |
20 |
21 |
22 |
23 | /lib
24 | runtime
25 |
26 | ${project.groupId}:${project.artifactId}
27 |
28 |
29 |
30 | /
31 |
32 | ${project.groupId}:${project.artifactId}
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/blade-lattice/src/main/java/com/bladejava/lattice/model/User.java:
--------------------------------------------------------------------------------
1 | package com.bladejava.lattice.model;
2 |
3 | /**
4 | * @author biezhi
5 | * @date 2018/6/4
6 | */
7 | public class User {
8 |
9 | private String username;
10 | private String password;
11 | private Integer age;
12 | private String nickname;
13 |
14 | public User() {
15 | }
16 |
17 | public User(String username, String password, Integer age, String nickname) {
18 | this.username = username;
19 | this.password = password;
20 | this.age = age;
21 | this.nickname = nickname;
22 | }
23 |
24 | public String getUsername() {
25 | return username;
26 | }
27 |
28 | public void setUsername(String username) {
29 | this.username = username;
30 | }
31 |
32 | public String getPassword() {
33 | return password;
34 | }
35 |
36 | public void setPassword(String password) {
37 | this.password = password;
38 | }
39 |
40 | public Integer getAge() {
41 | return age;
42 | }
43 |
44 | public void setAge(Integer age) {
45 | this.age = age;
46 | }
47 |
48 | public String getNickname() {
49 | return nickname;
50 | }
51 |
52 | public void setNickname(String nickname) {
53 | this.nickname = nickname;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/blade-download/src/main/java/com/bladejava/demo/download/DownloadApplication.java:
--------------------------------------------------------------------------------
1 | package com.bladejava.demo.download;
2 |
3 | import com.hellokaton.blade.Blade;
4 | import com.hellokaton.blade.mvc.http.ByteBody;
5 |
6 | import java.io.File;
7 |
8 | /**
9 | * 访问
10 | *
11 | * http://127.0.0.1:9000/download1
12 | * http://127.0.0.1:9000/download2
13 | *
14 | * @author biezhi
15 | * @date 2022/5/3
16 | * @since blade-2.1.0.BETA
17 | */
18 | public class DownloadApplication {
19 |
20 | public static void main(String[] args) {
21 | Blade.create()
22 | .get("/download1", ctx -> {
23 | File file = new File("blade-download/src/main/resources/static/octo.png");
24 | ctx.response().contentType("image/png");
25 | ctx.response().header("Content-Disposition", "attachment; filename=hello.png");
26 | ctx.response().body(ByteBody.of(file));
27 | })
28 | .get("/download2", ctx -> {
29 | String str = "hello world";
30 | ctx.response().contentType("text/plain; charset=UTF-8");
31 | ctx.response().header("Content-Disposition", "attachment; filename=hello.txt");
32 | ctx.response().body(ByteBody.of(str.getBytes()));
33 | })
34 | .start(DownloadApplication.class, args);
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/blade-anima/src/main/java/com/bladejava/anima/User.java:
--------------------------------------------------------------------------------
1 | package com.bladejava.anima;
2 |
3 | import com.hellokaton.anima.Model;
4 | import com.hellokaton.anima.annotation.Table;
5 |
6 | /**
7 | * User Entity
8 | *
9 | * default table name is 'users'
10 | *
11 | * @author biezhi
12 | * @date 2018-11-27
13 | */
14 | @Table(name = "t_user")
15 | public class User extends Model {
16 |
17 | private Integer id;
18 | private String username;
19 | private String password;
20 | private String realName;
21 | private Integer age;
22 |
23 | public Integer getId() {
24 | return id;
25 | }
26 |
27 | public void setId(Integer id) {
28 | this.id = id;
29 | }
30 |
31 | public String getUsername() {
32 | return username;
33 | }
34 |
35 | public void setUsername(String username) {
36 | this.username = username;
37 | }
38 |
39 | public String getPassword() {
40 | return password;
41 | }
42 |
43 | public void setPassword(String password) {
44 | this.password = password;
45 | }
46 |
47 | public String getRealName() {
48 | return realName;
49 | }
50 |
51 | public void setRealName(String realName) {
52 | this.realName = realName;
53 | }
54 |
55 | public Integer getAge() {
56 | return age;
57 | }
58 |
59 | public void setAge(Integer age) {
60 | this.age = age;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/blade-template/src/main/resources/templates/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 登陆页面
6 |
7 |
8 |
9 |
10 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/blade-test/src/main/java/com/bladejava/demo/controller/UserController.java:
--------------------------------------------------------------------------------
1 | package com.bladejava.demo.controller;
2 |
3 | import com.bladejava.demo.model.User;
4 | import com.bladejava.demo.service.UserService;
5 | import com.hellokaton.blade.annotation.Path;
6 | import com.hellokaton.blade.annotation.request.Body;
7 | import com.hellokaton.blade.annotation.request.PathParam;
8 | import com.hellokaton.blade.annotation.route.GET;
9 | import com.hellokaton.blade.annotation.route.POST;
10 | import com.hellokaton.blade.ioc.annotation.Inject;
11 | import com.hellokaton.blade.kit.StringKit;
12 | import com.hellokaton.blade.mvc.ui.ResponseType;
13 | import com.hellokaton.blade.mvc.ui.RestResponse;
14 |
15 | import java.util.Collections;
16 |
17 | /**
18 | * @author biezhi
19 | * @date 2018/5/31
20 | */
21 | @Path(value = "user", responseType = ResponseType.JSON)
22 | public class UserController {
23 |
24 | @Inject
25 | private UserService userService;
26 |
27 | @POST("save")
28 | public RestResponse> saveUser(@Body User user) {
29 | return RestResponse.ok(userService.saveUser(user));
30 | }
31 |
32 | @GET("list")
33 | public RestResponse> list() {
34 | return RestResponse.ok(Collections.singletonList(new User(123L, "biezhi")));
35 | }
36 |
37 | @GET("detail/:uid")
38 | public RestResponse> detail(@PathParam Long uid) {
39 | return RestResponse.ok(new User(uid, StringKit.rand(10)));
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/blade-verify-code/src/main/java/com/blade/demo/verifycode/VerifyCodeApplication.java:
--------------------------------------------------------------------------------
1 | package com.blade.demo.verifycode;
2 |
3 | import com.hellokaton.blade.Blade;
4 | import com.hellokaton.blade.options.HttpOptions;
5 | import com.hellokaton.blade.patchca.DefaultPatchca;
6 | import com.hellokaton.blade.patchca.PatchcaException;
7 |
8 | /**
9 | * Blade Patcha Example
10 | *
11 | * 1. generate code
12 | * http://127.0.0.1:9000/code
13 | *
14 | * 2. verify code
15 | * http://127.0.0.1:9000/verify?code=LmCGY
16 | *
17 | * @author hellokaton
18 | * @date 2022/5/4
19 | */
20 | public class VerifyCodeApplication {
21 |
22 | public static void main(String[] args) {
23 |
24 | // 这行代码应该放在启动时加载
25 | DefaultPatchca patchca = new DefaultPatchca();
26 |
27 | Blade.create()
28 | .get("/code", ctx -> {
29 | try {
30 | String code = patchca.render();
31 | System.out.println("verify code: " + code);
32 | } catch (PatchcaException e) {
33 | System.out.println("Patchca Error: " + e.getMessage());
34 | }
35 | })
36 | .get("/verify", ctx -> {
37 | String code = ctx.request().query("code", "CODE");
38 | boolean success = patchca.verify(code);
39 | ctx.text("verify result: " + success);
40 | })
41 | .http(HttpOptions::enableSession)
42 | .start(VerifyCodeApplication.class, args);
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/blade-mongo/src/main/java/com/blade/demo/mongo/IndexController.java:
--------------------------------------------------------------------------------
1 | package com.blade.demo.mongo;
2 |
3 | import com.hellokaton.blade.annotation.Path;
4 | import com.hellokaton.blade.annotation.route.GET;
5 | import com.mongodb.client.MongoCollection;
6 | import com.mongodb.client.MongoCursor;
7 | import org.bson.Document;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import java.util.Arrays;
12 |
13 | /**
14 | * @author biezhi
15 | * @date 2018/4/27
16 | */
17 | @Path
18 | public class IndexController {
19 |
20 | private static final Logger log = LoggerFactory.getLogger(IndexController.class);
21 |
22 | @GET("/read")
23 | public void read() {
24 | MongoCollection collection = MongoConfig.getMongoDatabase().getCollection("test");
25 | MongoCursor cursor = collection.find().iterator();
26 |
27 | try {
28 | while (cursor.hasNext()) {
29 | log.info(cursor.next().toJson());
30 | }
31 | } finally {
32 | cursor.close();
33 | }
34 | }
35 |
36 | @GET("/write")
37 | public void write() {
38 | MongoCollection collection = MongoConfig.getMongoDatabase().getCollection("test");
39 |
40 | Document doc = new Document("name", "MongoDB")
41 | .append("type", "database")
42 | .append("count", 1)
43 | .append("versions", Arrays.asList("v3.2", "v3.0", "v2.6"))
44 | .append("info", new Document("x", 203).append("y", 102));
45 |
46 | collection.insertOne(doc);
47 |
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/blade-ajax/src/main/java/com/blade/demo/ajax/User.java:
--------------------------------------------------------------------------------
1 | package com.blade.demo.ajax;
2 |
3 | import java.util.Date;
4 |
5 | /**
6 | * User
7 | */
8 | public class User {
9 |
10 | private Integer id;
11 | private String userName;
12 | private Integer age;
13 | private Date birthday;
14 |
15 | public User(){
16 |
17 | }
18 |
19 | public User(Integer id, String userName, Integer age, Date birthday){
20 | this.id = id;
21 | this.userName = userName;
22 | this.age = age;
23 | this.birthday = birthday;
24 | }
25 |
26 | /**
27 | * @return the id
28 | */
29 | public Integer getId() {
30 | return id;
31 | }
32 |
33 | /**
34 | * @param id the id to set
35 | */
36 | public void setId(Integer id) {
37 | this.id = id;
38 | }
39 |
40 | /**
41 | * @return the userName
42 | */
43 | public String getUserName() {
44 | return userName;
45 | }
46 |
47 | /**
48 | * @param userName the userName to set
49 | */
50 | public void setUserName(String userName) {
51 | this.userName = userName;
52 | }
53 |
54 | /**
55 | * @return the birthday
56 | */
57 | public Date getBirthday() {
58 | return birthday;
59 | }
60 |
61 | /**
62 | * @param birthday the birthday to set
63 | */
64 | public void setBirthday(Date birthday) {
65 | this.birthday = birthday;
66 | }
67 |
68 | /**
69 | * @return the age
70 | */
71 | public Integer getAge() {
72 | return age;
73 | }
74 |
75 | /**
76 | * @param age the age to set
77 | */
78 | public void setAge(Integer age) {
79 | this.age = age;
80 | }
81 |
82 | }
--------------------------------------------------------------------------------
/blade-cors/src/main/java/com/blade/demo/cors/User.java:
--------------------------------------------------------------------------------
1 | package com.blade.demo.cors;
2 |
3 | import java.util.Date;
4 |
5 | /**
6 | * User
7 | */
8 | public class User {
9 |
10 | private Integer id;
11 | private String userName;
12 | private Integer age;
13 | private Date birthday;
14 |
15 | public User(){
16 |
17 | }
18 |
19 | public User(Integer id, String userName, Integer age, Date birthday){
20 | this.id = id;
21 | this.userName = userName;
22 | this.age = age;
23 | this.birthday = birthday;
24 | }
25 |
26 | /**
27 | * @return the id
28 | */
29 | public Integer getId() {
30 | return id;
31 | }
32 |
33 | /**
34 | * @param id the id to set
35 | */
36 | public void setId(Integer id) {
37 | this.id = id;
38 | }
39 |
40 | /**
41 | * @return the userName
42 | */
43 | public String getUserName() {
44 | return userName;
45 | }
46 |
47 | /**
48 | * @param userName the userName to set
49 | */
50 | public void setUserName(String userName) {
51 | this.userName = userName;
52 | }
53 |
54 | /**
55 | * @return the birthday
56 | */
57 | public Date getBirthday() {
58 | return birthday;
59 | }
60 |
61 | /**
62 | * @param birthday the birthday to set
63 | */
64 | public void setBirthday(Date birthday) {
65 | this.birthday = birthday;
66 | }
67 |
68 | /**
69 | * @return the age
70 | */
71 | public Integer getAge() {
72 | return age;
73 | }
74 |
75 | /**
76 | * @param age the age to set
77 | */
78 | public void setAge(Integer age) {
79 | this.age = age;
80 | }
81 |
82 | }
--------------------------------------------------------------------------------
/blade-static/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | blade-demos
7 | com.hellokaton
8 | 0.0.1
9 |
10 | 4.0.0
11 |
12 | blade-static
13 |
14 |
15 | blade-static
16 |
17 |
18 | maven-assembly-plugin
19 |
20 | ${project.build.finalName}
21 | false
22 |
23 |
24 | com.hellokaton.staticdir.StaticApplication
25 |
26 |
27 |
28 | jar-with-dependencies
29 |
30 |
31 |
32 |
33 | make-assembly
34 | package
35 |
36 | single
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/blade-helloworld/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | blade-demos
7 | com.hellokaton
8 | 0.0.1
9 |
10 | 4.0.0
11 |
12 | blade-helloworld
13 |
14 |
15 | helloworld
16 |
17 |
18 | maven-assembly-plugin
19 |
20 | ${project.build.finalName}
21 | false
22 |
23 |
24 | com.blade.demo.helloworld.HelloApplication
25 |
26 |
27 |
28 | jar-with-dependencies
29 |
30 |
31 |
32 |
33 | make-assembly
34 | package
35 |
36 | single
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/blade-kit-example/src/main/java/com/blade/demo/kit/model/User.java:
--------------------------------------------------------------------------------
1 | package com.blade.demo.kit.model;
2 |
3 |
4 | import java.util.Date;
5 |
6 | /**
7 | * @author biezhi
8 | * @date 2017/12/20
9 | */
10 | public class User {
11 |
12 | private String username;
13 | private Integer age;
14 | private double money;
15 |
16 | // @JsonFormat(value = "yyyy年MM月dd日 HH:mm", type = MappingType.DATE_PATTEN)
17 | private Date birthday;
18 | private Boolean sex;
19 | private Byte status;
20 |
21 | public String getUsername() {
22 | return username;
23 | }
24 |
25 | public void setUsername(String username) {
26 | this.username = username;
27 | }
28 |
29 | public Integer getAge() {
30 | return age;
31 | }
32 |
33 | public void setAge(Integer age) {
34 | this.age = age;
35 | }
36 |
37 | public double getMoney() {
38 | return money;
39 | }
40 |
41 | public void setMoney(double money) {
42 | this.money = money;
43 | }
44 |
45 | public Date getBirthday() {
46 | return birthday;
47 | }
48 |
49 | public void setBirthday(Date birthday) {
50 | this.birthday = birthday;
51 | }
52 |
53 | public Boolean getSex() {
54 | return sex;
55 | }
56 |
57 | public void setSex(Boolean sex) {
58 | this.sex = sex;
59 | }
60 |
61 | public Byte getStatus() {
62 | return status;
63 | }
64 |
65 | public void setStatus(Byte status) {
66 | this.status = status;
67 | }
68 |
69 | @Override
70 | public String toString() {
71 | return "User(" +
72 | "username='" + username + '\'' +
73 | ", age=" + age +
74 | ", money=" + money +
75 | ", birthday=" + birthday +
76 | ", sex=" + sex +
77 | ", status=" + status +
78 | ')';
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/blade-task/src/main/java/com/blade/demo/task/TaskExample.java:
--------------------------------------------------------------------------------
1 | package com.blade.demo.task;
2 |
3 | import com.hellokaton.blade.ioc.annotation.Bean;
4 | import com.hellokaton.blade.kit.DateKit;
5 | import com.hellokaton.blade.task.TaskContext;
6 | import com.hellokaton.blade.task.TaskManager;
7 | import com.hellokaton.blade.task.annotation.Schedule;
8 |
9 | import java.time.LocalDateTime;
10 | import java.util.concurrent.atomic.AtomicInteger;
11 |
12 | /**
13 | * Task Example
14 | *
15 | * @author biezhi
16 | * @date 2018/4/12
17 | */
18 | @Bean
19 | public class TaskExample {
20 |
21 | /**
22 | * 每秒执行一次
23 | */
24 | @Schedule(cron = "* * * * * ?")
25 | public void one() {
26 | System.out.println("每秒钟执行一次,现在是: " + DateKit.toString(LocalDateTime.now()));
27 | }
28 |
29 | /**
30 | * 每五秒执行一次
31 | */
32 | @Schedule(name = "taskTwo", cron = "*/5 * * * * ?")
33 | public void two() {
34 | System.out.println("每五秒钟执行一次,现在是: " + DateKit.toString(LocalDateTime.now()));
35 | }
36 |
37 | private AtomicInteger size = new AtomicInteger();
38 |
39 | /**
40 | * 每秒执行一次,当 size == 3 时停止
41 | *
42 | * @param taskContext
43 | */
44 | @Schedule(cron = "* * * * * ?")
45 | public void three(TaskContext taskContext) {
46 | if (size.getAndIncrement() == 3) {
47 | return;
48 | }
49 | System.out.println("Task Three: " + size.get());
50 | }
51 |
52 | private AtomicInteger fourSize = new AtomicInteger();
53 |
54 | /**
55 | * 每秒执行一次,10秒后开始执行
56 | *
57 | * 使用静态方法 TaskManager.stopTask 停止任务
58 | */
59 | @Schedule(name = "fourTask", cron = "* * * * * ?", delay = 1000L)
60 | public void four() {
61 | if (fourSize.getAndIncrement() == 2) {
62 | TaskManager.stopTask("fourTask");
63 | return;
64 | }
65 | System.out.println("Four Task: " + fourSize.get());
66 | }
67 |
68 | @Schedule(name = "expression_demo", cron = "${task_exp}")
69 | public void expressionDemo() {
70 | System.out.println(LocalDateTime.now() + ": 我是表达式的例子");
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/blade-websocket/src/main/resources/static/main.css:
--------------------------------------------------------------------------------
1 | *, *:before, *:after {
2 | -moz-box-sizing: border-box;
3 | -webkit-box-sizing: border-box;
4 | box-sizing: border-box;
5 | }
6 |
7 | html {
8 | font-family: Helvetica, Arial, sans-serif;
9 | font-size: 100%;
10 | background: #333;
11 | }
12 |
13 | #page-wrapper {
14 | width: 650px;
15 | background: #FFF;
16 | padding: 1em;
17 | margin: 1em auto;
18 | border-top: 5px solid #69c773;
19 | box-shadow: 0 2px 10px rgba(0,0,0,0.8);
20 | }
21 |
22 | h1 {
23 | margin-top: 0;
24 | }
25 |
26 | #status {
27 | font-size: 0.9rem;
28 | margin-bottom: 1rem;
29 | }
30 |
31 | .open {
32 | color: green;
33 | }
34 |
35 | .closed {
36 | color: red;
37 | }
38 |
39 |
40 | ul {
41 | list-style: none;
42 | margin: 0;
43 | padding: 0;
44 | font-size: 0.95rem;
45 | }
46 |
47 | ul li {
48 | padding: 0.5rem 0.75rem;
49 | border-bottom: 1px solid #EEE;
50 | }
51 |
52 | ul li:first-child {
53 | border-top: 1px solid #EEE;
54 | }
55 |
56 | ul li span {
57 | display: inline-block;
58 | width: 90px;
59 | font-weight: bold;
60 | color: #999;
61 | font-size: 0.7rem;
62 | text-transform: uppercase;
63 | letter-spacing: 1px;
64 | }
65 |
66 | .sent {
67 | background-color: #F7F7F7;
68 | }
69 |
70 | .received {}
71 |
72 | #message-form {
73 | margin-top: 1.5rem;
74 | }
75 |
76 | textarea {
77 | width: 100%;
78 | padding: 0.5rem;
79 | font-size: 1rem;
80 | border: 1px solid #D9D9D9;
81 | border-radius: 3px;
82 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
83 | min-height: 100px;
84 | margin-bottom: 1rem;
85 | }
86 |
87 | button {
88 | display: inline-block;
89 | border-radius: 3px;
90 | border: none;
91 | font-size: 0.9rem;
92 | padding: 0.6rem 1em;
93 | color: white;
94 | margin: 0 0.25rem;
95 | text-align: center;
96 | background: #BABABA;
97 | border-bottom: 1px solid #999;
98 | }
99 |
100 | button[type="submit"] {
101 | background: #86b32d;
102 | border-bottom: 1px solid #5d7d1f;
103 | }
104 |
105 | button:hover {
106 | opacity: 0.75;
107 | cursor: pointer;
108 | }
109 |
--------------------------------------------------------------------------------
/blade-websocket/src/main/resources/static/main.js:
--------------------------------------------------------------------------------
1 | window.onload = function() {
2 |
3 | // Get references to elements on the page.
4 | var form = document.getElementById('message-form');
5 | var messageField = document.getElementById('message');
6 | var messagesList = document.getElementById('messages');
7 | var socketStatus = document.getElementById('status');
8 | var closeBtn = document.getElementById('close');
9 |
10 |
11 | // Create a new WebSocket.
12 | var socket = new WebSocket('ws://127.0.0.1:9000/chat');
13 |
14 | // Handle any errors that occur.
15 | socket.onerror = function(error) {
16 | console.log('WebSocket Error: ' + error);
17 | };
18 |
19 | // Show a connected message when the WebSocket is opened.
20 | socket.onopen = function(event) {
21 | socketStatus.innerHTML = '连接到: ' + event.currentTarget.url;
22 | socketStatus.className = 'open';
23 | };
24 |
25 |
26 | // Handle messages sent by the server.
27 | socket.onmessage = function(event) {
28 | var message = event.data;
29 | messagesList.innerHTML += '
Received:' + message + '';
30 | };
31 |
32 |
33 | // Show a disconnected message when the WebSocket is closed.
34 | socket.onclose = function(event) {
35 | socketStatus.innerHTML = '断开 WebSocket 连接';
36 | socketStatus.className = 'closed';
37 | };
38 |
39 |
40 | // Send a message when the form is submitted.
41 | form.onsubmit = function(e) {
42 | e.preventDefault();
43 |
44 | // Retrieve the message from the textarea.
45 | var message = messageField.value;
46 |
47 | // Send the message through the WebSocket.
48 | socket.send(message);
49 |
50 | // Add the message to the messages list.
51 | messagesList.innerHTML += 'Sent:' + message + '';
52 |
53 | // Clear out the message field.
54 | messageField.value = '';
55 |
56 | return false;
57 | };
58 |
59 |
60 | // Close the WebSocket connection when the close button is clicked.
61 | closeBtn.onclick = function(e) {
62 | e.preventDefault();
63 |
64 | // Close the WebSocket.
65 | socket.close();
66 |
67 | return false;
68 | };
69 |
70 | };
71 |
--------------------------------------------------------------------------------
/blade-vue-todolist/src/main/java/com/blade/demo/vue/TodoApplication.java:
--------------------------------------------------------------------------------
1 | package com.blade.demo.vue;
2 |
3 | import com.hellokaton.blade.Blade;
4 | import com.hellokaton.blade.kit.StringKit;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | /**
10 | * @author hellokaton
11 | * @date 2022/5/3
12 | */
13 | public class TodoApplication {
14 |
15 | private static final List todoList = new ArrayList<>();
16 |
17 | public static void main(String[] args) {
18 | Blade.create()
19 | .get("/", ctx -> ctx.render("index.html"))
20 | .post("/add", ctx -> {
21 | String todo = ctx.query("todo");
22 | if (StringKit.isNotBlank(todo)) {
23 | todoList.add(new Todo(todo, Todo.ACTIVE));
24 | }
25 | System.out.println("TodoList: " + todoList);
26 | ctx.text("success");
27 | })
28 | .post("/edit", ctx -> {
29 | String todo = ctx.query("oldTodo");
30 | if (StringKit.isNotBlank(todo)) {
31 | todoList.stream().filter(t -> t.getValue().equals(todo))
32 | .findFirst()
33 | .ifPresent(todoModel -> todoModel.setValue(todo));
34 | }
35 | System.out.println("TodoList: " + todoList);
36 | ctx.text("success");
37 | })
38 | .post("/remove", ctx -> {
39 | String todo = ctx.query("todo");
40 | if (StringKit.isNotBlank(todo)) {
41 | todoList.stream().filter(t -> t.getValue().equals(todo))
42 | .findFirst()
43 | .ifPresent(todoList::remove);
44 | }
45 | System.out.println("TodoList: " + todoList);
46 | ctx.text("success");
47 | })
48 | .post("/status/:status", ctx -> {
49 | String status = ctx.pathString("status");
50 | ctx.request().form("todo")
51 | .flatMap(todo -> todoList.stream().filter(t -> t.getValue().equals(todo))
52 | .findFirst()).ifPresent(todoModel -> todoModel.setStatus(status));
53 | System.out.println("TodoList: " + todoList);
54 | ctx.text("success");
55 | })
56 | .post("/clean", ctx -> {
57 | todoList.clear();
58 | ctx.text("success");
59 | })
60 | .start(TodoApplication.class, args);
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/blade-template/src/main/resources/static/main.js:
--------------------------------------------------------------------------------
1 | $( document ).ready(function() {
2 | // DOM ready
3 |
4 | // Test data
5 | /*
6 | * To test the script you should discomment the function
7 | * testLocalStorageData and refresh the page. The function
8 | * will load some test data and the loadProfile
9 | * will do the changes in the UI
10 | */
11 | // testLocalStorageData();
12 | // Load profile if it exits
13 | loadProfile();
14 | });
15 |
16 | /**
17 | * Function that gets the data of the profile in case
18 | * thar it has already saved in localstorage. Only the
19 | * UI will be update in case that all data is available
20 | *
21 | * A not existing key in localstorage return null
22 | *
23 | */
24 | function getLocalProfile(callback){
25 | var profileImgSrc = localStorage.getItem("PROFILE_IMG_SRC");
26 | var profileName = localStorage.getItem("PROFILE_NAME");
27 | var profileReAuthEmail = localStorage.getItem("PROFILE_REAUTH_EMAIL");
28 |
29 | if(profileName !== null
30 | && profileReAuthEmail !== null
31 | && profileImgSrc !== null) {
32 | callback(profileImgSrc, profileName, profileReAuthEmail);
33 | }
34 | }
35 |
36 | /**
37 | * Main function that load the profile if exists
38 | * in localstorage
39 | */
40 | function loadProfile() {
41 | if(!supportsHTML5Storage()) { return false; }
42 | // we have to provide to the callback the basic
43 | // information to set the profile
44 | getLocalProfile(function(profileImgSrc, profileName, profileReAuthEmail) {
45 | //changes in the UI
46 | $("#profile-img").attr("src",profileImgSrc);
47 | $("#profile-name").html(profileName);
48 | $("#reauth-email").html(profileReAuthEmail);
49 | $("#inputEmail").hide();
50 | $("#remember").hide();
51 | });
52 | }
53 |
54 | /**
55 | * function that checks if the browser supports HTML5
56 | * local storage
57 | *
58 | * @returns {boolean}
59 | */
60 | function supportsHTML5Storage() {
61 | try {
62 | return 'localStorage' in window && window['localStorage'] !== null;
63 | } catch (e) {
64 | return false;
65 | }
66 | }
67 |
68 | /**
69 | * Test data. This data will be safe by the web app
70 | * in the first successful login of a auth user.
71 | * To Test the scripts, delete the localstorage data
72 | * and comment this call.
73 | *
74 | * @returns {boolean}
75 | */
76 | function testLocalStorageData() {
77 | if(!supportsHTML5Storage()) { return false; }
78 | localStorage.setItem("PROFILE_IMG_SRC", "//lh3.googleusercontent.com/-6V8xOA6M7BA/AAAAAAAAAAI/AAAAAAAAAAA/rzlHcD0KYwo/photo.jpg?sz=120" );
79 | localStorage.setItem("PROFILE_NAME", "César Izquierdo Tello");
80 | localStorage.setItem("PROFILE_REAUTH_EMAIL", "oneaccount@gmail.com");
81 | }
--------------------------------------------------------------------------------
/blade-vue-todolist/src/main/resources/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Blade & Vue.js • TodoList
6 |
7 |
8 |
9 |
10 |
11 |
55 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Eclipse template
3 |
4 | .metadata
5 | bin/
6 | tmp/
7 | *.tmp
8 | *.bak
9 | *.swp
10 | *~.nib
11 | local.properties
12 | .settings/
13 | .loadpath
14 | .recommenders
15 | *.project
16 | *.classpath
17 | .settings
18 | *.iml
19 | .idea
20 |
21 | # External tool builders
22 | .externalToolBuilders/
23 |
24 | # Locally stored "Eclipse launch configurations"
25 | *.launch
26 |
27 | # PyDev specific (Python IDE for Eclipse)
28 | *.pydevproject
29 |
30 | # CDT-specific (C/C++ Development Tooling)
31 | .cproject
32 |
33 | # Java annotation processor (APT)
34 | .factorypath
35 |
36 | # PDT-specific (PHP Development Tools)
37 | .buildpath
38 |
39 | # sbteclipse plugin
40 | .target
41 |
42 | # Tern plugin
43 | .tern-project
44 |
45 | # TeXlipse plugin
46 | .texlipse
47 |
48 | # STS (Spring Tool Suite)
49 | .springBeans
50 |
51 | # Code Recommenders
52 | .recommenders/
53 |
54 | # Scala IDE specific (Scala & Java development for Eclipse)
55 | .cache-main
56 | .scala_dependencies
57 | .worksheet
58 | ### Maven template
59 | target/
60 | pom.xml.tag
61 | pom.xml.releaseBackup
62 | pom.xml.versionsBackup
63 | pom.xml.next
64 | release.properties
65 | dependency-reduced-pom.xml
66 | buildNumber.properties
67 | .mvn/timing.properties
68 |
69 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored)
70 | !/.mvn/wrapper/maven-wrapper.jar
71 | ### Java template
72 | # Compiled class file
73 | *.class
74 |
75 | # Log file
76 | *.log
77 |
78 | # BlueJ files
79 | *.ctxt
80 |
81 | # Mobile Tools for Java (J2ME)
82 | .mtj.tmp/
83 |
84 | # Package Files #
85 | *.jar
86 | *.war
87 | *.ear
88 | *.zip
89 | *.tar.gz
90 | *.rar
91 |
92 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
93 | hs_err_pid*
94 | ### JetBrains template
95 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
96 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
97 |
98 | # User-specific stuff:
99 | .idea/**/workspace.xml
100 | .idea/**/tasks.xml
101 | .idea/dictionaries
102 |
103 | # Sensitive or high-churn files:
104 | .idea/**/dataSources/
105 | .idea/**/dataSources.ids
106 | .idea/**/dataSources.xml
107 | .idea/**/dataSources.local.xml
108 | .idea/**/sqlDataSources.xml
109 | .idea/**/dynamic.xml
110 | .idea/**/uiDesigner.xml
111 |
112 | # Gradle:
113 | .idea/**/gradle.xml
114 | .idea/**/libraries
115 |
116 | # CMake
117 | cmake-build-debug/
118 |
119 | # Mongo Explorer plugin:
120 | .idea/**/mongoSettings.xml
121 |
122 | ## File-based project format:
123 | *.iws
124 |
125 | ## Plugin-specific files:
126 |
127 | # IntelliJ
128 | out/
129 |
130 | # mpeltonen/sbt-idea plugin
131 | .idea_modules/
132 |
133 | # JIRA plugin
134 | atlassian-ide-plugin.xml
135 |
136 | # Cursive Clojure plugin
137 | .idea/replstate.xml
138 |
139 | # Crashlytics plugin (for Android Studio and IntelliJ)
140 | com_crashlytics_export_strings.xml
141 | crashlytics.properties
142 | crashlytics-build.properties
143 | fabric.properties
144 |
145 |
--------------------------------------------------------------------------------
/blade-static/src/main/resources/static/main.css:
--------------------------------------------------------------------------------
1 | body, h1, h2, h3, h4, h5, h6, p, ul, ol, li, div, span, img, footer {
2 | margin: 0px;
3 | cursor: default;
4 |
5 | -moz-user-select: none;
6 | -webkit-user-select: none;
7 | -webkit-user-drag: none;
8 | }
9 | body {
10 | background: #e5e5e5 url(../images/background.png);
11 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
12 | font-size: 15px;
13 | }
14 | a {
15 | color: #333;
16 | text-decoration: none;
17 |
18 | -moz-user-select: none;
19 | -webkit-user-select: none;
20 | -webkit-user-drag: none;
21 |
22 | transition: 500ms;
23 | -o-transition: 500ms;
24 | -moz-transition: 500ms;
25 | -webkit-transition: 500ms;
26 | }
27 | a:hover {
28 | color: #707070;
29 | text-shadow: 1px 1px 5px #969696;
30 | }
31 | img {
32 | max-width: 100%;
33 | border-radius: 5px;
34 |
35 | -moz-user-select: none;
36 | -webkit-user-select: none;
37 | -webkit-user-drag: none;
38 |
39 | transition: 500ms;
40 | -o-transition: 500ms;
41 | -moz-transition: 500ms;
42 | -webkit-transition: 500ms;
43 | }
44 | img:hover {
45 | -moz-box-shadow: 0px 2px 8px 2px rgba(0, 0, 0, 0.1),1px 1px 30px 5px rgba(0, 0, 0, 0.2);
46 | box-shadow: 0px 2px 8px 2px rgba(0, 0, 0, 0.1),1px 1px 30px 5px rgba(0, 0, 0, 0.2);
47 |
48 | opacity: .8;
49 | }
50 |
51 | /* 侧边栏友情链接和回复列表中的头像 */
52 | img.avatar {
53 | float: left;
54 | height: 40px;
55 | width: 40px;
56 | margin-right: 10px;
57 | border-radius: 50px;
58 |
59 | transition: 500ms;
60 | -o-transition: 500ms;
61 | -moz-transition: 500ms;
62 | -webkit-transition: 500ms;
63 | }
64 |
65 |
66 | .article-list .main p {
67 | margin: 10px 0px;
68 | }
69 |
70 | /* 布局 */
71 |
72 | .container {
73 | max-width: 90%;
74 | margin: 0 auto;
75 | }
76 | .container:after {
77 | clear: both;
78 | content: "";
79 | display: table;
80 | }
81 | @media (min-width: 1170px) {
82 | .container {
83 | max-width: 80%;
84 | }
85 | }
86 |
87 |
88 | /* semantic框架提供的 label */
89 |
90 | .ui.ribbon.label {
91 | margin-top: 5px;
92 | margin-bottom: 5px;
93 | }
94 |
95 |
96 | /* 代码 */
97 |
98 | pre, code {
99 | border-radius: 5px;
100 | color: #DE3859;
101 | border: 1px solid #ddd;
102 | padding: 2px 5px;
103 | font-family: Consolas, 'Liberation Mono', Courier, monospace;
104 | }
105 | pre {
106 | padding: 10px;
107 | border-left: 4px solid #de3859;
108 | overflow: auto;
109 | }
110 | pre code {
111 | border: 0px;
112 | padding: 0px;
113 | }
114 |
115 |
116 | /* footer 部分 */
117 |
118 | footer {
119 | text-align: center;
120 | margin-top: 20px;
121 | color: rgb(136, 136, 136);
122 | font-size: 14px;
123 | }
124 | footer p {
125 | margin: 5px 0px;
126 | }
127 | footer a {
128 | color: rgb(136, 136, 136);
129 | }
130 | footer a:hover {
131 | color: rgb(200, 200, 200);
132 | }
133 |
134 | /* 光标 */
135 | .side .block .label:hover, .main .block .comments:hover, .main .block .round-date:hover {
136 | cursor: pointer;
137 | }
138 |
139 |
140 | #content {
141 | position:relative;
142 | margin-top: -180px;
143 | }
144 |
145 | .zocial:before {
146 | border: none;
147 | }
148 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.hellokaton
8 | blade-demos
9 | pom
10 | 0.0.1
11 |
12 |
13 | blade-helloworld
14 | blade-route
15 | blade-template
16 | blade-ajax
17 | blade-vue-todolist
18 | blade-upload
19 | blade-custom-banner
20 | blade-kit-example
21 | blade-freemarker
22 | blade-task
23 | blade-mongo
24 | blade-package
25 | blade-activemq
26 | blade-param
27 | blade-test
28 | blade-static
29 | blade-errorpage
30 | blade-lattice
31 | blade-anima
32 | blade-gzip
33 | blade-basic-auth
34 | blade-csrf-token
35 | blade-websocket
36 | blade-verify-code
37 | blade-download
38 | blade-cors
39 |
40 |
41 |
42 | UTF-8
43 | 2.1.1.RELEASE
44 |
45 |
46 |
47 |
48 |
49 | com.hellokaton
50 | blade-core
51 | ${blade-core.version}
52 |
53 |
54 |
55 |
56 |
57 | oss-release
58 | https://oss.sonatype.org/content/repositories/releases
59 |
60 | true
61 |
62 |
63 |
64 | oss-snapshots
65 | https://oss.sonatype.org/content/repositories/snapshots
66 |
67 | true
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | src/main/java
76 | false
77 |
78 |
79 | src/main/resources
80 | false
81 |
82 |
83 |
84 |
85 | maven-compiler-plugin
86 | 2.5.1
87 |
88 | 1.8
89 | 1.8
90 | UTF-8
91 |
92 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/blade-param/src/main/java/com/blade/demo/param/IndexController.java:
--------------------------------------------------------------------------------
1 | package com.blade.demo.param;
2 |
3 | import com.hellokaton.blade.annotation.Path;
4 | import com.hellokaton.blade.annotation.request.Body;
5 | import com.hellokaton.blade.annotation.request.Form;
6 | import com.hellokaton.blade.annotation.request.PathParam;
7 | import com.hellokaton.blade.annotation.request.Query;
8 | import com.hellokaton.blade.annotation.route.GET;
9 | import com.hellokaton.blade.annotation.route.POST;
10 | import com.hellokaton.blade.mvc.http.Request;
11 | import com.hellokaton.blade.mvc.http.Response;
12 | import com.hellokaton.blade.mvc.ui.ResponseType;
13 | import com.hellokaton.blade.mvc.ui.RestResponse;
14 |
15 | import java.util.Map;
16 | import java.util.Optional;
17 |
18 | /**
19 | * @author biezhi
20 | * @date 2018/5/30
21 | */
22 | @Path(responseType = ResponseType.JSON)
23 | public class IndexController {
24 |
25 | /**
26 | * http://127.0.0.1:9000/p1
27 | * http://127.0.0.1:9000/p1?test=hello
28 | *
29 | * @param test
30 | * @return
31 | */
32 | @GET("p1")
33 | public RestResponse p1(@Query String test) {
34 | return RestResponse.ok(test);
35 | }
36 |
37 | @POST("p2")
38 | public void p2(@Form String test, com.hellokaton.blade.mvc.http.Response response) {
39 | response.text(Optional.ofNullable(test).orElse("默认值"));
40 | }
41 |
42 | @GET("p3/:uid")
43 | public void p3(@PathParam Integer uid, Response response) {
44 | response.text("UID: " + uid);
45 | }
46 |
47 | @GET("p4")
48 | public void p4(Request request, Response response) {
49 | response.text("username: " + request.query("username", "默认值"));
50 | }
51 |
52 | @GET("p5")
53 | public RestResponse p5(User user) {
54 | return RestResponse.ok(user);
55 | }
56 |
57 | @GET("p6")
58 | public RestResponse p6(@Query(name = "user") User user) {
59 | return RestResponse.ok(user);
60 | }
61 |
62 | @GET("p7")
63 | public RestResponse p7(@Body User user) {
64 | return RestResponse.ok(user);
65 | }
66 |
67 | /**
68 | * curl -X POST \
69 | * http://127.0.0.1:9000/p8 \
70 | * -H 'content-type: application/json' \
71 | * -d '{"name":"{\"inoutTypeCode\":2,\"passDeviceCode\":\"TZ_001_65010078ZHONGDA_I7\",\"passTypeCode\":1,\"idnumber\":\"152825198404205136\",\"passTime\":\"2018-06-01 14:05:33\",\"name\":\"两伊。\",\"snapPhoto\":\"data:image/jpeg;base64,Qk12AQAAAAAAADYAAAAoAAAADQAAAAgAAAABABgAAAAAAEABAAAAAAAAAAAAAAAAAAAAAAAA////////////////////////////////////////////////////AP///////////////////////////////////////////////////wD///////////////////////////////////////////////////8A////////////////////////////////////////////////////AFpaWlpaWlpaWlpaWlpaWlpaWlRUVHt7e////////////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqKir///////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAANTU1////////////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAADU1Nf///////////////////wA=\",\"refId\":\"p9049vighuhg0r83dbfv7ip1f6\",\"idCardPhoto\":\"data:image/jpeg;base64,Qk12AQAAAAAAADYAAAAoAAAADQAAAAgAAAABABgAAAAAAEABAAAAAAAAAAAAAAAAAAAAAAAA////////////////////////////////////////////////////AP///////////////////////////////////////////////////wD///////////////////////////////////////////////////8A////////////////////////////////////////////////////AFpaWlpaWlpaWlpaWlpaWlpaWlRUVHt7e////////////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqKir///////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAANTU1////////////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAADU1Nf///////////////////wA=\"}"}'
72 | */
73 | @POST("p8")
74 | public RestResponse p8(@Body Map map) {
75 | return RestResponse.ok(map);
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/blade-template/src/main/resources/static/main.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Specific styles of signin component
3 | */
4 | /*
5 | * General styles
6 | */
7 | body, html {
8 | height: 100%;
9 | background-repeat: no-repeat;
10 | background-image: linear-gradient(rgb(104, 145, 162), rgb(12, 97, 33));
11 | }
12 |
13 | .card-container.card {
14 | max-width: 350px;
15 | padding: 40px 40px;
16 | }
17 |
18 | .btn {
19 | font-weight: 700;
20 | height: 36px;
21 | -moz-user-select: none;
22 | -webkit-user-select: none;
23 | user-select: none;
24 | cursor: default;
25 | }
26 |
27 | /*
28 | * Card component
29 | */
30 | .card {
31 | background-color: #F7F7F7;
32 | /* just in case there no content*/
33 | padding: 20px 25px 30px;
34 | margin: 0 auto 25px;
35 | margin-top: 50px;
36 | /* shadows and rounded borders */
37 | -moz-border-radius: 2px;
38 | -webkit-border-radius: 2px;
39 | border-radius: 2px;
40 | -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
41 | -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
42 | box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
43 | }
44 |
45 | .profile-img-card {
46 | width: 96px;
47 | height: 96px;
48 | margin: 0 auto 10px;
49 | display: block;
50 | -moz-border-radius: 50%;
51 | -webkit-border-radius: 50%;
52 | border-radius: 50%;
53 | }
54 |
55 | /*
56 | * Form styles
57 | */
58 | .profile-name-card {
59 | font-size: 16px;
60 | font-weight: bold;
61 | text-align: center;
62 | margin: 10px 0 0;
63 | min-height: 1em;
64 | }
65 |
66 | .reauth-email {
67 | display: block;
68 | color: #404040;
69 | line-height: 2;
70 | margin-bottom: 10px;
71 | font-size: 14px;
72 | text-align: center;
73 | overflow: hidden;
74 | text-overflow: ellipsis;
75 | white-space: nowrap;
76 | -moz-box-sizing: border-box;
77 | -webkit-box-sizing: border-box;
78 | box-sizing: border-box;
79 | }
80 |
81 | .form-signin #inputEmail,
82 | .form-signin #inputPassword {
83 | direction: ltr;
84 | height: 44px;
85 | font-size: 16px;
86 | }
87 |
88 | .form-signin input[type=email],
89 | .form-signin input[type=password],
90 | .form-signin input[type=text],
91 | .form-signin button {
92 | width: 100%;
93 | display: block;
94 | margin-bottom: 10px;
95 | z-index: 1;
96 | position: relative;
97 | -moz-box-sizing: border-box;
98 | -webkit-box-sizing: border-box;
99 | box-sizing: border-box;
100 | }
101 |
102 | .form-signin .form-control:focus {
103 | border-color: rgb(104, 145, 162);
104 | outline: 0;
105 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgb(104, 145, 162);
106 | box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgb(104, 145, 162);
107 | }
108 |
109 | .btn.btn-signin {
110 | /*background-color: #4d90fe; */
111 | background-color: rgb(104, 145, 162);
112 | /* background-color: linear-gradient(rgb(104, 145, 162), rgb(12, 97, 33));*/
113 | padding: 0px;
114 | font-weight: 700;
115 | font-size: 14px;
116 | height: 36px;
117 | -moz-border-radius: 3px;
118 | -webkit-border-radius: 3px;
119 | border-radius: 3px;
120 | border: none;
121 | -o-transition: all 0.218s;
122 | -moz-transition: all 0.218s;
123 | -webkit-transition: all 0.218s;
124 | transition: all 0.218s;
125 | }
126 |
127 | .btn.btn-signin:hover,
128 | .btn.btn-signin:active,
129 | .btn.btn-signin:focus {
130 | background-color: rgb(12, 97, 33);
131 | }
132 |
133 | .forgot-password {
134 | color: rgb(104, 145, 162);
135 | }
136 |
137 | .forgot-password:hover,
138 | .forgot-password:active,
139 | .forgot-password:focus{
140 | color: rgb(12, 97, 33);
141 | }
--------------------------------------------------------------------------------
/blade-package/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | blade-demos
7 | com.hellokaton
8 | 0.0.1
9 |
10 | 4.0.0
11 | blade-package
12 |
13 |
14 |
15 | dev
16 |
17 | dev
18 |
19 |
20 |
21 | true
22 |
23 |
24 |
25 |
26 | src/main/java
27 | false
28 |
29 |
30 | src/main/resources
31 | false
32 |
33 |
34 | src/main/test
35 | false
36 |
37 |
38 | src/test/resources
39 | false
40 |
41 |
42 |
43 |
44 |
45 | prod
46 |
47 | prod
48 |
49 |
50 |
51 |
52 | src/main/java
53 | false
54 |
55 | **/*.java
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | maven-compiler-plugin
67 |
68 | 1.8
69 | 1.8
70 | UTF-8
71 |
72 |
73 |
74 | maven-assembly-plugin
75 |
76 | false
77 |
78 | package.xml
79 |
80 | ${project.build.directory}/dist/
81 |
82 |
83 |
84 | make-assembly
85 | package
86 |
87 | single
88 |
89 |
90 |
91 |
92 |
93 | org.apache.maven.plugins
94 | maven-jar-plugin
95 | 2.4
96 |
97 |
98 |
99 | com.blade.demo.HelloApplication
100 | lib/
101 | true
102 |
103 |
104 | resources/
105 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // 使用 IntelliSense 了解相关属性。
3 | // 悬停以查看现有属性的描述。
4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "java",
9 | "name": "Debug (Launch)-AjaxApplication",
10 | "request": "launch",
11 | "cwd": "${workspaceFolder}",
12 | "console": "internalConsole",
13 | "stopOnEntry": false,
14 | "mainClass": "com.blade.demo.ajax.AjaxApplication",
15 | "projectName": "blade-ajax",
16 | "args": ""
17 | },
18 | {
19 | "type": "java",
20 | "name": "Debug (Launch)-CustomApplication",
21 | "request": "launch",
22 | "cwd": "${workspaceFolder}",
23 | "console": "internalConsole",
24 | "stopOnEntry": false,
25 | "mainClass": "com.blade.demo.custom.CustomApplication",
26 | "projectName": "blade-custom-banner",
27 | "args": ""
28 | },
29 | {
30 | "type": "java",
31 | "name": "Debug (Launch)-FreeMarkerApplication",
32 | "request": "launch",
33 | "cwd": "${workspaceFolder}",
34 | "console": "internalConsole",
35 | "stopOnEntry": false,
36 | "mainClass": "com.blade.demo.freemarker.FreeMarkerApplication",
37 | "projectName": "blade-freemarker",
38 | "args": ""
39 | },
40 | {
41 | "type": "java",
42 | "name": "Debug (Launch)-HelloApplication",
43 | "request": "launch",
44 | "cwd": "${workspaceFolder}",
45 | "console": "internalConsole",
46 | "stopOnEntry": false,
47 | "mainClass": "com.blade.demo.helloworld.HelloApplication",
48 | "projectName": "blade-helloworld",
49 | "args": ""
50 | },
51 | {
52 | "type": "java",
53 | "name": "Debug (Launch)-JSONKitExample",
54 | "request": "launch",
55 | "cwd": "${workspaceFolder}",
56 | "console": "internalConsole",
57 | "stopOnEntry": false,
58 | "mainClass": "com.blade.demo.kit.JSONKitExample",
59 | "projectName": "blade-kit-example",
60 | "args": ""
61 | },
62 | {
63 | "type": "java",
64 | "name": "Debug (Launch)-HelloApplication",
65 | "request": "launch",
66 | "cwd": "${workspaceFolder}",
67 | "console": "internalConsole",
68 | "stopOnEntry": false,
69 | "mainClass": "com.blade.demo.HelloApplication",
70 | "projectName": "blade-package",
71 | "args": ""
72 | },
73 | {
74 | "type": "java",
75 | "name": "Debug (Launch)-RouteApplication",
76 | "request": "launch",
77 | "cwd": "${workspaceFolder}",
78 | "console": "internalConsole",
79 | "stopOnEntry": false,
80 | "mainClass": "com.blade.demo.route.RouteApplication",
81 | "projectName": "blade-route",
82 | "args": ""
83 | },
84 | {
85 | "type": "java",
86 | "name": "Debug (Launch)-TplApplication",
87 | "request": "launch",
88 | "cwd": "${workspaceFolder}",
89 | "console": "internalConsole",
90 | "stopOnEntry": false,
91 | "mainClass": "com.blade.demo.tpl.TplApplication",
92 | "projectName": "blade-template",
93 | "args": ""
94 | },
95 | {
96 | "type": "java",
97 | "name": "Debug (Launch)-UploadApplication",
98 | "request": "launch",
99 | "cwd": "${workspaceFolder}",
100 | "console": "internalConsole",
101 | "stopOnEntry": false,
102 | "mainClass": "com.blade.demo.upload.UploadApplication",
103 | "projectName": "blade-upload",
104 | "args": ""
105 | },
106 | {
107 | "type": "java",
108 | "name": "Debug (Launch)-TodoApplication",
109 | "request": "launch",
110 | "cwd": "${workspaceFolder}",
111 | "console": "internalConsole",
112 | "stopOnEntry": false,
113 | "mainClass": "com.blade.demo.vue.TodoApplication",
114 | "projectName": "blade-vue-todolist",
115 | "args": ""
116 | },
117 | {
118 | "type": "java",
119 | "name": "Debug (Attach)",
120 | "request": "attach",
121 | "hostName": "localhost",
122 | "port": 0
123 | }
124 | ]
125 | }
--------------------------------------------------------------------------------
/blade-vue-todolist/src/main/resources/static/app.js:
--------------------------------------------------------------------------------
1 | // Full spec-compliant TodoMVC with localStorage persistence
2 | // and hash-based routing in ~120 effective lines of JavaScript.
3 |
4 | // localStorage persistence
5 | var STORAGE_KEY = 'todos-vuejs-2.0'
6 | var todoStorage = {
7 | fetch: function () {
8 | var todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]')
9 | todos.forEach(function (todo, index) {
10 | todo.id = index
11 | });
12 | todoStorage.uid = todos.length
13 | return todos
14 | },
15 | save: function (todos) {
16 | localStorage.setItem(STORAGE_KEY, JSON.stringify(todos))
17 | }
18 | };
19 |
20 | // visibility filters
21 | var filters = {
22 | all: function (todos) {
23 | return todos
24 | },
25 | active: function (todos) {
26 | return todos.filter(function (todo) {
27 | return !todo.completed
28 | })
29 | },
30 | completed: function (todos) {
31 | return todos.filter(function (todo) {
32 | return todo.completed
33 | })
34 | }
35 | };
36 |
37 | // app Vue instance
38 | var app = new Vue({
39 | // app initial state
40 | data: {
41 | todos: todoStorage.fetch(),
42 | newTodo: '',
43 | editedTodo: null,
44 | visibility: 'all'
45 | },
46 |
47 | // watch todos change for localStorage persistence
48 | watch: {
49 | todos: {
50 | handler: function (todos) {
51 | todoStorage.save(todos)
52 | },
53 | deep: true
54 | }
55 | },
56 |
57 | // computed properties
58 | // http://vuejs.org/guide/computed.html
59 | computed: {
60 | filteredTodos: function () {
61 | return filters[this.visibility](this.todos)
62 | },
63 | remaining: function () {
64 | return filters.active(this.todos).length
65 | },
66 | allDone: {
67 | get: function () {
68 | return this.remaining === 0
69 | },
70 | set: function (value) {
71 | this.todos.forEach(function (todo) {
72 | todo.completed = value
73 | })
74 | }
75 | }
76 | },
77 |
78 | filters: {
79 | pluralize: function (n) {
80 | return n === 1 ? 'item' : 'items'
81 | }
82 | },
83 |
84 | // methods that implement data logic.
85 | // note there's no DOM manipulation here at all.
86 | methods: {
87 | addTodo: function () {
88 | var value = this.newTodo && this.newTodo.trim()
89 | if (!value) {
90 | return
91 | }
92 | this.todos.push({
93 | id: todoStorage.uid++,
94 | title: value,
95 | completed: false
96 | });
97 | $.post('/add', {todo: value}, function (data) {
98 | });
99 | this.newTodo = ''
100 | },
101 |
102 | removeTodo: function (todo) {
103 | this.todos.splice(this.todos.indexOf(todo), 1);
104 | $.post('/remove', {todo: todo}, function (data) {
105 |
106 | });
107 | },
108 | editTodo: function (todo) {
109 | this.beforeEditCache = todo.title;
110 | this.editedTodo = todo;
111 | },
112 | doneEdit: function (todo) {
113 | if (!this.editedTodo) {
114 | return
115 | }
116 | this.editedTodo = null;
117 | todo.title = todo.title.trim()
118 | if (!todo.title) {
119 | this.removeTodo(todo)
120 | }
121 | console.log(this.editedTodo.title);
122 | },
123 | cancelEdit: function (todo) {
124 | this.editedTodo = null;
125 | todo.title = this.beforeEditCache
126 | },
127 | removeCompleted: function () {
128 | this.todos = filters.active(this.todos);
129 | $.post('/status/active', {todo: this.todos[0]}, function (data) {
130 |
131 | });
132 | }
133 | },
134 |
135 | // a custom directive to wait for the DOM to be updated
136 | // before focusing on the input field.
137 | // http://vuejs.org/guide/custom-directive.html
138 | directives: {
139 | 'todo-focus': function (el, binding) {
140 | if (binding.value) {
141 | el.focus()
142 | }
143 | }
144 | }
145 | });
146 |
147 | // handle routing
148 | function onHashChange() {
149 | var visibility = window.location.hash.replace(/#\/?/, '');
150 | if (filters[visibility]) {
151 | app.visibility = visibility
152 | } else {
153 | window.location.hash = '';
154 | app.visibility = 'all'
155 | }
156 | }
157 |
158 | window.addEventListener('hashchange', onHashChange)
159 | onHashChange();
160 |
161 | // mount
162 | app.$mount('.todoapp')
--------------------------------------------------------------------------------
/blade-vue-todolist/src/main/resources/static/base.js:
--------------------------------------------------------------------------------
1 | /* global _ */
2 | (function () {
3 | 'use strict';
4 |
5 | /* jshint ignore:start */
6 | // Underscore's Template Module
7 | // Courtesy of underscorejs.org
8 | var _ = (function (_) {
9 | _.defaults = function (object) {
10 | if (!object) {
11 | return object;
12 | }
13 | for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {
14 | var iterable = arguments[argsIndex];
15 | if (iterable) {
16 | for (var key in iterable) {
17 | if (object[key] == null) {
18 | object[key] = iterable[key];
19 | }
20 | }
21 | }
22 | }
23 | return object;
24 | }
25 |
26 | // By default, Underscore uses ERB-style template delimiters, change the
27 | // following template settings to use alternative delimiters.
28 | _.templateSettings = {
29 | evaluate : /<%([\s\S]+?)%>/g,
30 | interpolate : /<%=([\s\S]+?)%>/g,
31 | escape : /<%-([\s\S]+?)%>/g
32 | };
33 |
34 | // When customizing `templateSettings`, if you don't want to define an
35 | // interpolation, evaluation or escaping regex, we need one that is
36 | // guaranteed not to match.
37 | var noMatch = /(.)^/;
38 |
39 | // Certain characters need to be escaped so that they can be put into a
40 | // string literal.
41 | var escapes = {
42 | "'": "'",
43 | '\\': '\\',
44 | '\r': 'r',
45 | '\n': 'n',
46 | '\t': 't',
47 | '\u2028': 'u2028',
48 | '\u2029': 'u2029'
49 | };
50 |
51 | var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
52 |
53 | // JavaScript micro-templating, similar to John Resig's implementation.
54 | // Underscore templating handles arbitrary delimiters, preserves whitespace,
55 | // and correctly escapes quotes within interpolated code.
56 | _.template = function(text, data, settings) {
57 | var render;
58 | settings = _.defaults({}, settings, _.templateSettings);
59 |
60 | // Combine delimiters into one regular expression via alternation.
61 | var matcher = new RegExp([
62 | (settings.escape || noMatch).source,
63 | (settings.interpolate || noMatch).source,
64 | (settings.evaluate || noMatch).source
65 | ].join('|') + '|$', 'g');
66 |
67 | // Compile the template source, escaping string literals appropriately.
68 | var index = 0;
69 | var source = "__p+='";
70 | text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
71 | source += text.slice(index, offset)
72 | .replace(escaper, function(match) { return '\\' + escapes[match]; });
73 |
74 | if (escape) {
75 | source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
76 | }
77 | if (interpolate) {
78 | source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
79 | }
80 | if (evaluate) {
81 | source += "';\n" + evaluate + "\n__p+='";
82 | }
83 | index = offset + match.length;
84 | return match;
85 | });
86 | source += "';\n";
87 |
88 | // If a variable is not specified, place data values in local scope.
89 | if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
90 |
91 | source = "var __t,__p='',__j=Array.prototype.join," +
92 | "print=function(){__p+=__j.call(arguments,'');};\n" +
93 | source + "return __p;\n";
94 |
95 | try {
96 | render = new Function(settings.variable || 'obj', '_', source);
97 | } catch (e) {
98 | e.source = source;
99 | throw e;
100 | }
101 |
102 | if (data) return render(data, _);
103 | var template = function(data) {
104 | return render.call(this, data, _);
105 | };
106 |
107 | // Provide the compiled function source as a convenience for precompilation.
108 | template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
109 |
110 | return template;
111 | };
112 |
113 | return _;
114 | })({});
115 |
116 | if (location.hostname === 'todomvc.com') {
117 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
118 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
119 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
120 | })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
121 | ga('create', 'UA-31081062-1', 'auto');
122 | ga('send', 'pageview');
123 | }
124 | /* jshint ignore:end */
125 |
126 | function redirect() {
127 | if (location.hostname === 'tastejs.github.io') {
128 | location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com');
129 | }
130 | }
131 |
132 | function findRoot() {
133 | var base = location.href.indexOf('examples/');
134 | return location.href.substr(0, base);
135 | }
136 |
137 | function getFile(file, callback) {
138 | if (!location.host) {
139 | return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.');
140 | }
141 |
142 | var xhr = new XMLHttpRequest();
143 |
144 | xhr.open('GET', findRoot() + file, true);
145 | xhr.send();
146 |
147 | xhr.onload = function () {
148 | if (xhr.status === 200 && callback) {
149 | callback(xhr.responseText);
150 | }
151 | };
152 | }
153 |
154 | function Learn(learnJSON, config) {
155 | if (!(this instanceof Learn)) {
156 | return new Learn(learnJSON, config);
157 | }
158 |
159 | var template, framework;
160 |
161 | if (typeof learnJSON !== 'object') {
162 | try {
163 | learnJSON = JSON.parse(learnJSON);
164 | } catch (e) {
165 | return;
166 | }
167 | }
168 |
169 | if (config) {
170 | template = config.template;
171 | framework = config.framework;
172 | }
173 |
174 | if (!template && learnJSON.templates) {
175 | template = learnJSON.templates.todomvc;
176 | }
177 |
178 | if (!framework && document.querySelector('[data-framework]')) {
179 | framework = document.querySelector('[data-framework]').dataset.framework;
180 | }
181 |
182 | this.template = template;
183 |
184 | if (learnJSON.backend) {
185 | this.frameworkJSON = learnJSON.backend;
186 | this.frameworkJSON.issueLabel = framework;
187 | this.append({
188 | backend: true
189 | });
190 | } else if (learnJSON[framework]) {
191 | this.frameworkJSON = learnJSON[framework];
192 | this.frameworkJSON.issueLabel = framework;
193 | this.append();
194 | }
195 |
196 | this.fetchIssueCount();
197 | }
198 |
199 | Learn.prototype.append = function (opts) {
200 | var aside = document.createElement('aside');
201 | aside.innerHTML = _.template(this.template, this.frameworkJSON);
202 | aside.className = 'learn';
203 |
204 | if (opts && opts.backend) {
205 | // Remove demo link
206 | var sourceLinks = aside.querySelector('.source-links');
207 | var heading = sourceLinks.firstElementChild;
208 | var sourceLink = sourceLinks.lastElementChild;
209 | // Correct link path
210 | var href = sourceLink.getAttribute('href');
211 | sourceLink.setAttribute('href', href.substr(href.lastIndexOf('http')));
212 | sourceLinks.innerHTML = heading.outerHTML + sourceLink.outerHTML;
213 | } else {
214 | // Localize demo links
215 | var demoLinks = aside.querySelectorAll('.demo-link');
216 | Array.prototype.forEach.call(demoLinks, function (demoLink) {
217 | if (demoLink.getAttribute('href').substr(0, 4) !== 'http') {
218 | demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href'));
219 | }
220 | });
221 | }
222 |
223 | document.body.className = (document.body.className + ' learn-bar').trim();
224 | document.body.insertAdjacentHTML('afterBegin', aside.outerHTML);
225 | };
226 |
227 | Learn.prototype.fetchIssueCount = function () {
228 | var issueLink = document.getElementById('issue-count-link');
229 | if (issueLink) {
230 | var url = issueLink.href.replace('https://github.com', 'https://api.github.com/repos');
231 | var xhr = new XMLHttpRequest();
232 | xhr.open('GET', url, true);
233 | xhr.onload = function (e) {
234 | var parsedResponse = JSON.parse(e.target.responseText);
235 | if (parsedResponse instanceof Array) {
236 | var count = parsedResponse.length;
237 | if (count !== 0) {
238 | issueLink.innerHTML = 'This app has ' + count + ' open issues';
239 | document.getElementById('issue-count').style.display = 'inline';
240 | }
241 | }
242 | };
243 | xhr.send();
244 | }
245 | };
246 |
247 | redirect();
248 | getFile('learn.json', Learn);
249 | })();
--------------------------------------------------------------------------------
/blade-vue-todolist/src/main/resources/static/app.css:
--------------------------------------------------------------------------------
1 |
2 | hr {
3 | margin: 20px 0;
4 | border: 0;
5 | border-top: 1px dashed #c5c5c5;
6 | border-bottom: 1px dashed #f7f7f7;
7 | }
8 |
9 | .learn a {
10 | font-weight: normal;
11 | text-decoration: none;
12 | color: #b83f45;
13 | }
14 |
15 | .learn a:hover {
16 | text-decoration: underline;
17 | color: #787e7e;
18 | }
19 |
20 | .learn h3,
21 | .learn h4,
22 | .learn h5 {
23 | margin: 10px 0;
24 | font-weight: 500;
25 | line-height: 1.2;
26 | color: #000;
27 | }
28 |
29 | .learn h3 {
30 | font-size: 24px;
31 | }
32 |
33 | .learn h4 {
34 | font-size: 18px;
35 | }
36 |
37 | .learn h5 {
38 | margin-bottom: 0;
39 | font-size: 14px;
40 | }
41 |
42 | .learn ul {
43 | padding: 0;
44 | margin: 0 0 30px 25px;
45 | }
46 |
47 | .learn li {
48 | line-height: 20px;
49 | }
50 |
51 | .learn p {
52 | font-size: 15px;
53 | font-weight: 300;
54 | line-height: 1.3;
55 | margin-top: 0;
56 | margin-bottom: 0;
57 | }
58 |
59 | #issue-count {
60 | display: none;
61 | }
62 |
63 | .quote {
64 | border: none;
65 | margin: 20px 0 60px 0;
66 | }
67 |
68 | .quote p {
69 | font-style: italic;
70 | }
71 |
72 | .quote p:before {
73 | content: '“';
74 | font-size: 50px;
75 | opacity: .15;
76 | position: absolute;
77 | top: -20px;
78 | left: 3px;
79 | }
80 |
81 | .quote p:after {
82 | content: '”';
83 | font-size: 50px;
84 | opacity: .15;
85 | position: absolute;
86 | bottom: -42px;
87 | right: 3px;
88 | }
89 |
90 | .quote footer {
91 | position: absolute;
92 | bottom: -40px;
93 | right: 0;
94 | }
95 |
96 | .quote footer img {
97 | border-radius: 3px;
98 | }
99 |
100 | .quote footer a {
101 | margin-left: 5px;
102 | vertical-align: middle;
103 | }
104 |
105 | .speech-bubble {
106 | position: relative;
107 | padding: 10px;
108 | background: rgba(0, 0, 0, .04);
109 | border-radius: 5px;
110 | }
111 |
112 | .speech-bubble:after {
113 | content: '';
114 | position: absolute;
115 | top: 100%;
116 | right: 30px;
117 | border: 13px solid transparent;
118 | border-top-color: rgba(0, 0, 0, .04);
119 | }
120 |
121 | .learn-bar > .learn {
122 | position: absolute;
123 | width: 272px;
124 | top: 8px;
125 | left: -300px;
126 | padding: 10px;
127 | border-radius: 5px;
128 | background-color: rgba(255, 255, 255, .6);
129 | transition-property: left;
130 | transition-duration: 500ms;
131 | }
132 |
133 | @media (min-width: 899px) {
134 | .learn-bar {
135 | width: auto;
136 | padding-left: 300px;
137 | }
138 |
139 | .learn-bar > .learn {
140 | left: 8px;
141 | }
142 | }
143 |
144 | html,
145 | body {
146 | margin: 0;
147 | padding: 0;
148 | }
149 |
150 | button {
151 | margin: 0;
152 | padding: 0;
153 | border: 0;
154 | background: none;
155 | font-size: 100%;
156 | vertical-align: baseline;
157 | font-family: inherit;
158 | font-weight: inherit;
159 | color: inherit;
160 | -webkit-appearance: none;
161 | appearance: none;
162 | -webkit-font-smoothing: antialiased;
163 | -moz-osx-font-smoothing: grayscale;
164 | }
165 |
166 | body {
167 | font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
168 | line-height: 1.4em;
169 | background: #f5f5f5;
170 | color: #4d4d4d;
171 | min-width: 230px;
172 | max-width: 550px;
173 | margin: 0 auto;
174 | -webkit-font-smoothing: antialiased;
175 | -moz-osx-font-smoothing: grayscale;
176 | font-weight: 300;
177 | }
178 |
179 | :focus {
180 | outline: 0;
181 | }
182 |
183 | .hidden {
184 | display: none;
185 | }
186 |
187 | .todoapp {
188 | background: #fff;
189 | margin: 130px 0 40px 0;
190 | position: relative;
191 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
192 | 0 25px 50px 0 rgba(0, 0, 0, 0.1);
193 | }
194 |
195 | .todoapp input::-webkit-input-placeholder {
196 | font-style: italic;
197 | font-weight: 300;
198 | color: #e6e6e6;
199 | }
200 |
201 | .todoapp input::-moz-placeholder {
202 | font-style: italic;
203 | font-weight: 300;
204 | color: #e6e6e6;
205 | }
206 |
207 | .todoapp input::input-placeholder {
208 | font-style: italic;
209 | font-weight: 300;
210 | color: #e6e6e6;
211 | }
212 |
213 | .todoapp h1 {
214 | position: absolute;
215 | top: -155px;
216 | width: 100%;
217 | font-size: 100px;
218 | font-weight: 100;
219 | text-align: center;
220 | color: rgba(175, 47, 47, 0.15);
221 | -webkit-text-rendering: optimizeLegibility;
222 | -moz-text-rendering: optimizeLegibility;
223 | text-rendering: optimizeLegibility;
224 | }
225 |
226 | .new-todo,
227 | .edit {
228 | position: relative;
229 | margin: 0;
230 | width: 100%;
231 | font-size: 24px;
232 | font-family: inherit;
233 | font-weight: inherit;
234 | line-height: 1.4em;
235 | border: 0;
236 | color: inherit;
237 | padding: 6px;
238 | border: 1px solid #999;
239 | box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
240 | box-sizing: border-box;
241 | -webkit-font-smoothing: antialiased;
242 | -moz-osx-font-smoothing: grayscale;
243 | }
244 |
245 | .new-todo {
246 | padding: 16px 16px 16px 60px;
247 | border: none;
248 | background: rgba(0, 0, 0, 0.003);
249 | box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
250 | }
251 |
252 | .main {
253 | position: relative;
254 | z-index: 2;
255 | border-top: 1px solid #e6e6e6;
256 | }
257 |
258 | label[for='toggle-all'] {
259 | display: none;
260 | }
261 |
262 | .toggle-all {
263 | position: absolute;
264 | top: -55px;
265 | left: -12px;
266 | width: 60px;
267 | height: 34px;
268 | text-align: center;
269 | border: none; /* Mobile Safari */
270 | }
271 |
272 | .toggle-all:before {
273 | content: '❯';
274 | font-size: 22px;
275 | color: #e6e6e6;
276 | padding: 10px 27px 10px 27px;
277 | }
278 |
279 | .toggle-all:checked:before {
280 | color: #737373;
281 | }
282 |
283 | .todo-list {
284 | margin: 0;
285 | padding: 0;
286 | list-style: none;
287 | }
288 |
289 | .todo-list li {
290 | position: relative;
291 | font-size: 24px;
292 | border-bottom: 1px solid #ededed;
293 | }
294 |
295 | .todo-list li:last-child {
296 | border-bottom: none;
297 | }
298 |
299 | .todo-list li.editing {
300 | border-bottom: none;
301 | padding: 0;
302 | }
303 |
304 | .todo-list li.editing .edit {
305 | display: block;
306 | width: 506px;
307 | padding: 12px 16px;
308 | margin: 0 0 0 43px;
309 | }
310 |
311 | .todo-list li.editing .view {
312 | display: none;
313 | }
314 |
315 | .todo-list li .toggle {
316 | text-align: center;
317 | width: 40px;
318 | /* auto, since non-WebKit browsers doesn't support input styling */
319 | height: auto;
320 | position: absolute;
321 | top: 0;
322 | bottom: 0;
323 | margin: auto 0;
324 | border: none; /* Mobile Safari */
325 | -webkit-appearance: none;
326 | appearance: none;
327 | }
328 |
329 | .todo-list li .toggle:after {
330 | content: url('data:image/svg+xml;utf8,');
331 | }
332 |
333 | .todo-list li .toggle:checked:after {
334 | content: url('data:image/svg+xml;utf8,');
335 | }
336 |
337 | .todo-list li label {
338 | word-break: break-all;
339 | padding: 15px 60px 15px 15px;
340 | margin-left: 45px;
341 | display: block;
342 | line-height: 1.2;
343 | transition: color 0.4s;
344 | }
345 |
346 | .todo-list li.completed label {
347 | color: #d9d9d9;
348 | text-decoration: line-through;
349 | }
350 |
351 | .todo-list li .destroy {
352 | display: none;
353 | position: absolute;
354 | top: 0;
355 | right: 10px;
356 | bottom: 0;
357 | width: 40px;
358 | height: 40px;
359 | margin: auto 0;
360 | font-size: 30px;
361 | color: #cc9a9a;
362 | margin-bottom: 11px;
363 | transition: color 0.2s ease-out;
364 | }
365 |
366 | .todo-list li .destroy:hover {
367 | color: #af5b5e;
368 | }
369 |
370 | .todo-list li .destroy:after {
371 | content: '×';
372 | }
373 |
374 | .todo-list li:hover .destroy {
375 | display: block;
376 | }
377 |
378 | .todo-list li .edit {
379 | display: none;
380 | }
381 |
382 | .todo-list li.editing:last-child {
383 | margin-bottom: -1px;
384 | }
385 |
386 | .footer {
387 | color: #777;
388 | padding: 10px 15px;
389 | height: 20px;
390 | text-align: center;
391 | border-top: 1px solid #e6e6e6;
392 | }
393 |
394 | .footer:before {
395 | content: '';
396 | position: absolute;
397 | right: 0;
398 | bottom: 0;
399 | left: 0;
400 | height: 50px;
401 | overflow: hidden;
402 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
403 | 0 8px 0 -3px #f6f6f6,
404 | 0 9px 1px -3px rgba(0, 0, 0, 0.2),
405 | 0 16px 0 -6px #f6f6f6,
406 | 0 17px 2px -6px rgba(0, 0, 0, 0.2);
407 | }
408 |
409 | .todo-count {
410 | float: left;
411 | text-align: left;
412 | }
413 |
414 | .todo-count strong {
415 | font-weight: 300;
416 | }
417 |
418 | .filters {
419 | margin: 0;
420 | padding: 0;
421 | list-style: none;
422 | position: absolute;
423 | right: 0;
424 | left: 0;
425 | }
426 |
427 | .filters li {
428 | display: inline;
429 | }
430 |
431 | .filters li a {
432 | color: inherit;
433 | margin: 3px;
434 | padding: 3px 7px;
435 | text-decoration: none;
436 | border: 1px solid transparent;
437 | border-radius: 3px;
438 | }
439 |
440 | .filters li a:hover {
441 | border-color: rgba(175, 47, 47, 0.1);
442 | }
443 |
444 | .filters li a.selected {
445 | border-color: rgba(175, 47, 47, 0.2);
446 | }
447 |
448 | .clear-completed,
449 | html .clear-completed:active {
450 | float: right;
451 | position: relative;
452 | line-height: 20px;
453 | text-decoration: none;
454 | cursor: pointer;
455 | }
456 |
457 | .clear-completed:hover {
458 | text-decoration: underline;
459 | }
460 |
461 | .info {
462 | margin: 65px auto 0;
463 | color: #bfbfbf;
464 | font-size: 10px;
465 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
466 | text-align: center;
467 | }
468 |
469 | .info p {
470 | line-height: 1;
471 | }
472 |
473 | .info a {
474 | color: inherit;
475 | text-decoration: none;
476 | font-weight: 400;
477 | }
478 |
479 | .info a:hover {
480 | text-decoration: underline;
481 | }
482 |
483 | /*
484 | Hack to remove background from Mobile Safari.
485 | Can't use it globally since it destroys checkboxes in Firefox
486 | */
487 | @media screen and (-webkit-min-device-pixel-ratio:0) {
488 | .toggle-all,
489 | .todo-list li .toggle {
490 | background: none;
491 | }
492 |
493 | .todo-list li .toggle {
494 | height: 40px;
495 | }
496 |
497 | .toggle-all {
498 | -webkit-transform: rotate(90deg);
499 | transform: rotate(90deg);
500 | -webkit-appearance: none;
501 | appearance: none;
502 | }
503 | }
504 |
505 | @media (max-width: 430px) {
506 | .footer {
507 | height: 50px;
508 | }
509 |
510 | .filters {
511 | bottom: 10px;
512 | }
513 | }
--------------------------------------------------------------------------------
/blade-vue-todolist/src/main/resources/static/director.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | //
4 | // Generated on Tue Dec 16 2014 12:13:47 GMT+0100 (CET) by Charlie Robbins, Paolo Fragomeni & the Contributors (Using Codesurgeon).
5 | // Version 1.2.6
6 | //
7 |
8 | (function (exports) {
9 |
10 | /*
11 | * browser.js: Browser specific functionality for director.
12 | *
13 | * (C) 2011, Charlie Robbins, Paolo Fragomeni, & the Contributors.
14 | * MIT LICENSE
15 | *
16 | */
17 |
18 | var dloc = document.location;
19 |
20 | function dlocHashEmpty() {
21 | // Non-IE browsers return '' when the address bar shows '#'; Director's logic
22 | // assumes both mean empty.
23 | return dloc.hash === '' || dloc.hash === '#';
24 | }
25 |
26 | var listener = {
27 | mode: 'modern',
28 | hash: dloc.hash,
29 | history: false,
30 |
31 | check: function () {
32 | var h = dloc.hash;
33 | if (h != this.hash) {
34 | this.hash = h;
35 | this.onHashChanged();
36 | }
37 | },
38 |
39 | fire: function () {
40 | if (this.mode === 'modern') {
41 | this.history === true ? window.onpopstate() : window.onhashchange();
42 | }
43 | else {
44 | this.onHashChanged();
45 | }
46 | },
47 |
48 | init: function (fn, history) {
49 | var self = this;
50 | this.history = history;
51 |
52 | if (!Router.listeners) {
53 | Router.listeners = [];
54 | }
55 |
56 | function onchange(onChangeEvent) {
57 | for (var i = 0, l = Router.listeners.length; i < l; i++) {
58 | Router.listeners[i](onChangeEvent);
59 | }
60 | }
61 |
62 | //note IE8 is being counted as 'modern' because it has the hashchange event
63 | if ('onhashchange' in window && (document.documentMode === undefined
64 | || document.documentMode > 7)) {
65 | // At least for now HTML5 history is available for 'modern' browsers only
66 | if (this.history === true) {
67 | // There is an old bug in Chrome that causes onpopstate to fire even
68 | // upon initial page load. Since the handler is run manually in init(),
69 | // this would cause Chrome to run it twise. Currently the only
70 | // workaround seems to be to set the handler after the initial page load
71 | // http://code.google.com/p/chromium/issues/detail?id=63040
72 | setTimeout(function() {
73 | window.onpopstate = onchange;
74 | }, 500);
75 | }
76 | else {
77 | window.onhashchange = onchange;
78 | }
79 | this.mode = 'modern';
80 | }
81 | else {
82 | //
83 | // IE support, based on a concept by Erik Arvidson ...
84 | //
85 | var frame = document.createElement('iframe');
86 | frame.id = 'state-frame';
87 | frame.style.display = 'none';
88 | document.body.appendChild(frame);
89 | this.writeFrame('');
90 |
91 | if ('onpropertychange' in document && 'attachEvent' in document) {
92 | document.attachEvent('onpropertychange', function () {
93 | if (event.propertyName === 'location') {
94 | self.check();
95 | }
96 | });
97 | }
98 |
99 | window.setInterval(function () { self.check(); }, 50);
100 |
101 | this.onHashChanged = onchange;
102 | this.mode = 'legacy';
103 | }
104 |
105 | Router.listeners.push(fn);
106 |
107 | return this.mode;
108 | },
109 |
110 | destroy: function (fn) {
111 | if (!Router || !Router.listeners) {
112 | return;
113 | }
114 |
115 | var listeners = Router.listeners;
116 |
117 | for (var i = listeners.length - 1; i >= 0; i--) {
118 | if (listeners[i] === fn) {
119 | listeners.splice(i, 1);
120 | }
121 | }
122 | },
123 |
124 | setHash: function (s) {
125 | // Mozilla always adds an entry to the history
126 | if (this.mode === 'legacy') {
127 | this.writeFrame(s);
128 | }
129 |
130 | if (this.history === true) {
131 | window.history.pushState({}, document.title, s);
132 | // Fire an onpopstate event manually since pushing does not obviously
133 | // trigger the pop event.
134 | this.fire();
135 | } else {
136 | dloc.hash = (s[0] === '/') ? s : '/' + s;
137 | }
138 | return this;
139 | },
140 |
141 | writeFrame: function (s) {
142 | // IE support...
143 | var f = document.getElementById('state-frame');
144 | var d = f.contentDocument || f.contentWindow.document;
145 | d.open();
146 | d.write("