{"id":21126122,"url":"https://github.com/shigebeyond/jkmvc","last_synced_at":"2025-07-08T23:31:51.358Z","repository":{"id":57737264,"uuid":"91640060","full_name":"shigebeyond/jkmvc","owner":"shigebeyond","description":"Jkmvc is an elegant, powerful and lightweight MVC \u0026 ORM framework built using kotlin. It aims to be swift, secure, and small. It will turn java's heavy development into kotlin's simple pleasure. No spring.","archived":false,"fork":false,"pushed_at":"2023-08-15T05:59:00.000Z","size":7352,"stargazers_count":89,"open_issues_count":0,"forks_count":14,"subscribers_count":17,"default_branch":"master","last_synced_at":"2023-08-15T06:46:04.575Z","etag":null,"topics":["async-servlet","kotlin","mvc","orm","servlet3","web","web-framework"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shigebeyond.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-05-18T02:29:30.000Z","updated_at":"2023-05-19T07:09:20.000Z","dependencies_parsed_at":"2023-01-28T16:45:16.323Z","dependency_job_id":null,"html_url":"https://github.com/shigebeyond/jkmvc","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shigebeyond%2Fjkmvc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shigebeyond%2Fjkmvc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shigebeyond%2Fjkmvc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shigebeyond%2Fjkmvc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shigebeyond","download_url":"https://codeload.github.com/shigebeyond/jkmvc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225470849,"owners_count":17479366,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async-servlet","kotlin","mvc","orm","servlet3","web","web-framework"],"created_at":"2024-11-20T04:39:25.676Z","updated_at":"2024-11-20T04:39:26.307Z","avatar_url":"https://github.com/shigebeyond.png","language":"Kotlin","funding_links":[],"categories":["开发框架"],"sub_categories":["Web框架"],"readme":"[GitHub](https://github.com/shigebeyond/jkmvc) | [Gitee](https://gitee.com/shigebeyond/jkmvc) \n\n# jkmvc\nJkmvc is an elegant, powerful and lightweight MVC web framework built using kotlin. It aims to be swift, secure, and small. It will turn java's heavy development into kotlin's simple pleasure.\n\nInspired by 2 php frameworks: [kohana](https://github.com/kohana/kohana) and [skmvc](https://github.com/shigebeyond/skmvc)\n\n[Document](#Document)\n\n[中文文档](#中文文档)\n\n[性能跟开发效率对比](https://github.com/shigebeyond/jkmvc-benchmark)\n\n# Introduction - web\n\nTake `jkmvc/jkmvc-example` for example.\n\n## 1 Add jkmvc-http dependecies\n\n1. gradle\n```\ndependencies{\n   compile \"net.jkcode.jkmvc:jkmvc-http:1.9.0\n   // If you want to use embedded jetty\n   compile \"net.jkcode.jkmvc:jkmvc-server-jetty:1.9.0\n}\n```\n\n2. maven\n```\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.jkcode.jkmvc\u003c/groupId\u003e\n    \u003cartifactId\u003ejkmvc-http\u003c/artifactId\u003e\n    \u003cversion\u003e1.9.0\u003c/version\u003e\n\u003c/dependency\u003e\n\u003c!-- If you want to use embedded jetty --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.jkcode.jkmvc\u003c/groupId\u003e\n    \u003cartifactId\u003ejkmvc-server-jetty\u003c/artifactId\u003e\n    \u003cversion\u003e1.9.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## 2 Configure JkFilter in web.xml\n\nJkFilter is a Filter for your web application\n\nvim src/main/webapp/WEB-INF/web.xml\n\n```\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cweb-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xmlns:web=\"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd\" id=\"WebApp_ID\" version=\"2.5\"\u003e\n\t\u003cfilter\u003e\n\t\t\u003cfilter-name\u003ejkmvc\u003c/filter-name\u003e\n\t\t\u003cfilter-class\u003enet.jkcode.jkmvc.http.JkFilter\u003c/filter-class\u003e\n\t\u003c/filter\u003e\n\n\t\u003cfilter-mapping\u003e\n\t\t\u003cfilter-name\u003ejkmvc\u003c/filter-name\u003e\n\t\t\u003curl-pattern\u003e/*\u003c/url-pattern\u003e\n\t\u003c/filter-mapping\u003e\n\u003c/web-app\u003e\n```\n\n## 3 Create Controller\n\nController handles request, and render data to response.\n\nIt has property `req` to represent request, `res` to represent response.\n\n```\npackage net.jkcode.jkmvc.example.controller\n\nimport net.jkcode.jkmvc.http.Controller\n\n/**\n * 主页\n */\nclass WelcomeController: Controller() {\n\n    /**\n     * 主页\n     */\n    public fun index() {\n        res.renderHtml(\"hello world\");\n    }\n\n}\n```\n\n## 4 Register Controller\n\nconfigure controller classes's package paths\n\nvim src/main/resources/http.yaml\n\n```\n# 是否调试\ndebug: true\n# 静态文件的扩展名\n# static file extension\nstaticFileExts: gif|jpg|jpeg|png|bmp|ico|svg|swf|js|css|eot|ttf|woff\n# controller类所在的包路径\n# controller classes's package paths\ncontrollerPackages:\n    - net.jkcode.jkmvc.example.controller\n```\n\n## 5 Gradle config jetty plugin\n\nvim build.gradle\n\n```\napply plugin: 'org.akhikhl.gretty'\n\n// 启动jetty\ngretty{\n    // server 配置\n    servletContainer 'jetty9' // 'tomcat8'\n    httpPort 8080\n    managedClassReload true // 热部署\n    scanInterval 1 // 热部署的扫描间隔，当值为0时，不扫描新class，不热部署\n\n    // 调试: gradle appRunDebug\n    debugPort 5006 // 运行jetty的jvm独立于运行gradle的jvm, 因此也使用独立的调试端口\n    debugSuspend true\n\n    // webapp 配置\n    contextPath \"/${project.name}\"\n    inplaceMode \"hard\" // 资源目录 src/main/webapp\n}\n```\n\n## 5 Run web server\n\n`gradle appRun -x test`\n\n![](img/runserver.png)\n\n## 6 Visit web page\n\nvisit http://localhost:8080/jkmvc-example/\n\n![](img/webpage.png)\n\n# Introduction - view\n\n## 1 Render View in Controller\n\n```\npackage net.jkcode.jkmvc.example.controller\n\nimport net.jkcode.jkmvc.http.Controller\n\n/**\n * 主页\n */\nclass WelcomeController: Controller() {\n\n    /**\n     * 显示jsp视图\n     * render jsp view\n     */\n    public fun jsp(){\n        res.renderView(view(\"index\" /* view file */, mapOf(\"name\" to \"shijianhang\") /* view data */))\n    }\n\n}\n```\n\n## 2 Create jsp view\n\nI regret that we cannot write kotlin in jsp.\n\nvim src/main/webapp/index.jsp\n\n```\n\u003c%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%\u003e\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n\u003cmeta charset=\"utf-8\"\u003e\n\u003ctitle\u003ejkmvc\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\nHello \u003c%= request.getAttribute(\"name\") %\u003e\u003cbr/\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n## 3 Visit web page\n\nvisit http://localhost:8080/jkmvc-example/welcome/jsp\n\n![](img/webview.png)\n\n\n# Introduction - orm\n\nOrm　provides object-oriented way to mainpulate db data.\n\nIt has 2 concepts:\n\n1 Orm meta data: include information as follows\n\n1.1 mapping from object to table\n\n1.2 mapping from object's property to table's column\n\n1.3 mapping from object's property to other object\n\n2 Orm object | Model\n\n2.1 visit property\n\nyou can use operator `[]` to visit orm object's property, and also use property delegate `public var id:Int by property\u003cInt\u003e();` to visit it\n\n2.2 method\n\n`queryBuilder()` return a query builder to query data from table\n\n`create()` create data\n\n`update()` update data\n\n`delete()` delete data\n\n## 1 Add dependency\n\n1. gradle\n```\ncompile \"net.jkcode.jkmvc:jkmvc-orm:1.9.0\"\n```\n\n2. maven\n```\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.jkcode.jkmvc\u003c/groupId\u003e\n    \u003cartifactId\u003ejkmvc-orm\u003c/artifactId\u003e\n    \u003cversion\u003e1.9.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## 2 Create tables\n\nuser table\n\n```\nCREATE TABLE `user` (\n  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户编号',\n  `name` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名',\n  `age` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '年龄',\n  `avatar` varchar(250) DEFAULT NULL COMMENT '头像',\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8 COMMENT='用户'\n```\n\naddress table\n\n```\nCREATE TABLE `address` (\n  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '地址编号',\n  `user_id` int(11) unsigned NOT NULL COMMENT '用户编号',\n  `addr` varchar(50) NOT NULL DEFAULT '' COMMENT '地址',\n  `tel` varchar(50) NOT NULL DEFAULT '' COMMENT '电话',\n  `name` varchar(50) NOT NULL DEFAULT '' COMMENT '用户名',\n  `is_home` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '是否是家庭住址',\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 COMMENT='地址';\n```\n\n## 3 Create Model\n\nuse model, extends Orm\n\n```\npackage net.jkcode.jkmvc.example.model\n\nimport net.jkcode.jkmvc.orm.OrmMeta\nimport net.jkcode.jkmvc.orm.Orm\n\n/**\n * 用户模型\n * User　model\n */\nclass UserModel(id:Int? = null): Orm(id) {\n    // 伴随对象就是元数据\n    // company object is meta data for model\n    companion object m: OrmMeta(UserModel::class){\n        init {\n            // 添加标签 + 规则\n            // add label and rule for field\n            addRule(\"name\", \"姓名\", \"notEmpty\");\n            addRule(\"age\", \"年龄\", \"between(1,120)\");\n\n            // 添加关联关系\n            // add relaction for other model\n            hasOne(\"home\", AddressModel::class){ query -\u003e\n                query.where(\"is_home\", 1)\n            }\n            hasMany(\"addresses\", AddressModel::class)\n        }\n    }\n\n    // 代理属性读写\n    // delegate property\n    public var id:Int by property\u003cInt\u003e();\n\n    public var name:String by property\u003cString\u003e();\n\n    public var age:Int by property\u003cInt\u003e();\n\n    public var avatar:String? by property\u003cString?\u003e();\n\n    // 关联地址：一个用户有一个地址\n    // relate to AddressModel: user has a home address\n    public var home:AddressModel by property\u003cAddressModel\u003e();\n\n    // 关联地址：一个用户有多个地址\n    // relate to AddressModel: user has many addresses\n    public var addresses:List\u003cAddressModel\u003e by property\u003cList\u003cAddressModel\u003e\u003e();\n}\n```\n\naddress model, extends Orm\n\n```\npackage net.jkcode.jkmvc.example.model\n\nimport net.jkcode.jkmvc.orm.OrmMeta\nimport net.jkcode.jkmvc.orm.Orm\n\n/**\n * 地址模型\n */\nclass AddressModel(id:Int? = null): Orm(id) {\n    // 伴随对象就是元数据\n    // company object is meta data for model\n    companion object m: OrmMeta(AddressModel::class){\n        init {\n            // 添加标签 + 规则\n            // add label and rule for field\n            addRule(\"user_id\", \"用户\", \"notEmpty\");\n            addRule(\"addr\", \"地址\", \"notEmpty\");\n            addRule(\"tel\", \"电话\", \"notEmpty \u0026\u0026 digit\");\n\n            // 添加关联关系\n            // add relaction for other model\n            belongsTo(\"user\", UserModel::class, \"user_id\")\n        }\n    }\n\n    // 代理属性读写\n    // delegate property\n    public var id:Int by property\u003cInt\u003e();\n\n    public var user_id:Int by property\u003cInt\u003e();\n\n    public var addr:String by property\u003cString\u003e();\n\n    public var tel:String by property\u003cString\u003e();\n\n    public var isHome:Int by property();\n\n    // 关联用户：一个地址从属于一个用户\n    public var user:UserModel by property\u003cUserModel\u003e()\n}\n```\n\n## 4 Use Model in Controller\n\n```\npackage net.jkcode.jkmvc.example.controller\n\nimport net.jkcode.jkutil.common.format\nimport net.jkcode.jkutil.common.httpLogger\nimport net.jkcode.jkmvc.example.model.UserModel\nimport net.jkcode.jkmvc.http.controller.Controller\nimport net.jkcode.jkmvc.http.fromRequest\nimport net.jkcode.jkmvc.http.isPost\nimport net.jkcode.jkmvc.http.isUpload\nimport net.jkcode.jkmvc.http.session.Auth\nimport net.jkcode.jkmvc.orm.OrmQueryBuilder\nimport net.jkcode.jkmvc.orm.isLoaded\nimport java.util.*\n\n\n/**\n * 用户管理\n * user manage\n */\nclass UserController: Controller()\n{\n    /**\n     * action前置处理\n     */\n    public override fun before() {\n        // 如检查权限\n        httpLogger.info(\"action前置处理\")\n    }\n\n    /**\n     * action后置处理\n     */\n    public override fun after() {\n        // 如记录日志\n        httpLogger.info(\"action后置处理\")\n    }\n\n    /**\n     * 列表页\n     * list page\n     */\n    public fun index()\n    {\n        val query: OrmQueryBuilder = UserModel.queryBuilder()\n        // 统计用户个数 | count users\n        val counter:OrmQueryBuilder = query.clone() as OrmQueryBuilder // 复制query builder\n        val count = counter.count()\n        // 查询所有用户 | find all users\n        val users = query.findModels\u003cUserModel\u003e()\n        // 渲染视图 | render view\n        res.renderView(view(\"user/index\", mapOf(\"count\" to count, \"users\" to users)))\n    }\n\n    /**\n     * 详情页\n     * detail page\n     */\n    public fun detail()\n    {\n        // 获得路由参数id: 2种写法 | 2 ways to get route parameter: \"id\"\n        // val id = req.getInt(\"id\");\n        val id:Int? = req[\"id\"] // req[\"xxx\"]\n        // 查询单个用户 | find a user\n        //val user = UserModel.queryBuilder().where(\"id\", id).findModel\u003cUserModel\u003e()\n        val user = UserModel(id)\n        if(!user.isLoaded()){\n            res.renderHtml(\"用户[$id]不存在\")\n            return\n        }\n        // 渲染视图 | render view\n        val view = view(\"user/detail\")\n        view[\"user\"] = user; // 设置视图参数 | set view data\n        res.renderView(view)\n    }\n\n    /**\n     * 新建页\n     * new page\n     */\n    public fun new()\n    {\n        // 处理请求 | handle request\n        if(req.isPost){ //  post请求：保存表单数据 | post request: save form data\n            // 创建空的用户 | create user model\n            val user = UserModel()\n            // 获得请求参数：3种写法 | 3 ways to get request parameter\n            /* // 1 req.getParameter(\"xxx\");\n            user.name = req.getParameter(\"name\")!!;\n            user.age = req.getInt(\"age\", 0)!!; // 带默认值 | default value\n            */\n            // 2 req[\"xxx\"]\n            user.name = req[\"name\"]!!;\n            user.age = req[\"age\"]!!;\n\n            // 3 Orm.fromRequest(req)\n            user.fromRequest(req)\n            user.create(); // create user\n            // 重定向到列表页 | redirect to list page\n            redirect(\"user/index\");\n        }else{ // get请求： 渲染视图 | get request: render view\n            val view = view() // 默认视图为action名： user/new | default view's name = action：　user/new\n            res.renderView(view)\n        }\n    }\n\n    /**\n     * 编辑页\n     * edit page\n     */\n    public fun edit()\n    {\n        // 查询单个用户 | find a user\n        val id: Int = req[\"id\"]!!\n        val user = UserModel(id)\n        if(!user.isLoaded()){\n            res.renderHtml(\"用户[\" + req[\"id\"] + \"]不存在\")\n            return\n        }\n        // 处理请求 | handle request\n        if(req.isPost){ //  post请求：保存表单数据 | post request: save form data\n            // 获得请求参数：3种写法 | 3 way to get request parameter\n            /* // 1 req.getParameter(\"xxx\");\n            user.name = req.getParameter(\"name\")!!;\n            user.age = req.getInt(\"age\", 0)!!; // 带默认值 | default value\n            */\n            /*// 2 req[\"xxx\"]\n            user.name = req[\"name\"]!!;\n            user.age = req[\"age\"]!!;\n            */\n            // 3 Orm.fromRequest(req)\n            user.fromRequest(req)\n            user.update() // update user\n            // 重定向到列表页 | redirect to list page\n            redirect(\"user/index\");\n        }else{ // get请求： 渲染视图 | get request: render view\n            val view = view() // 默认视图为action名： user/edit | default view's name = action：　user/edit\n            view[\"user\"] = user; // 设置视图参数 |  set view data\n            res.renderView(view)\n        }\n    }\n\n    /**\n     * 删除\n     * delete action\n     */\n    public fun delete()\n    {\n        val id:Int? = req[\"id\"]\n        // 查询单个用户 | find a user\n        val user = UserModel(id)\n        if(!user.isLoaded()){\n            res.renderHtml(\"用户[$id]不存在\")\n            return\n        }\n        // 删除 | delete user\n        user.delete();\n        // 重定向到列表页 | redirect to list page\n        redirect(\"user/index\");\n    }\n\n    /**\n     * 上传头像\n     * upload avatar\n     */\n    public fun uploadAvatar()\n    {\n        // 查询单个用户 | find a user\n        val id: Int = req[\"id\"]!!\n        val user = UserModel(id)\n        if(!user.isLoaded()){\n            res.renderHtml(\"用户[\" + req[\"id\"] + \"]不存在\")\n            return\n        }\n\n        // 检查并处理上传文件 | check and handle upload request\n        if(req.isUpload){ // 检查上传请求 | check upload request\n            user.avatar = req.storePartFileAndGetRelativePath(\"avatar\")!!\n            user.update()\n        }\n\n        // 重定向到详情页 | redirect to detail page\n        redirect(\"user/detail/$id\");\n    }\n\n    /**\n     * 登录\n     */\n    public fun login(){\n        if(req.isPost){ // post请求\n            val user = Auth.instance().login(req[\"username\"]!!, req[\"password\"]!!);\n            if(user == null)\n                res.renderHtml(\"登录失败\")\n            else\n                redirect(\"user/login\")\n        }else{ // get请求\n            res.renderView(view())\n        }\n    }\n\n    /**\n     * 登录\n     */\n    public fun logout(){\n        Auth.instance().logout()\n        redirect(\"user/login\")\n    }\n}\n```\n\n# demo\n\ndownload source and run web server\n\n```\ngit clone https://github.com/shigebeyond/jkmvc.git\ncd jkmvc\ngradle :jkmvc-example:appRun\n```\n\nvisit url\n\nhttp://localhost:8080/jkmvc-example/user/index\n\n![](img/actionindex.png)\n\nhttp://localhost:8080/jkmvc-example/user/detail\n\n![](img/actiondetail.png)\n\nhttp://localhost:8080/jkmvc-example/user/new\n\n![](img/actionnew.png)\n\nhttp://localhost:8080/jkmvc-example/user/edit\n\n![](img/actionedit.png)\n\n# gradle command for build\n\n```\ngradle :jkmvc-orm:build -x test\ngradle :jkmvc-http:build -x test\ngradle :jkmvc-example:build -x test\n```\n\n# Document\n## http module\n1. [getting started](doc/http/getting_started.md)\n2. [controller](doc/http/controller.md)\n3. [request](doc/http/request.md)\n4. [response](doc/http/response.md)\n5. [route](doc/http/route.md)\n6. [upload](doc/http/upload.md)\n7. [request handling flow](doc/http/flow.md)\n8. [cookie](doc/http/cookie.md)\n9. [session](doc/http/session.md)\n\n## db module\n10. [getting started](doc/db/getting_started.md)\n11. [query](doc/db/query.md)\n12. [query builder](doc/db/query_builder.md)\n13. [db expression](doc/db/expr.md)\n\n## orm module\n14. [getting_started](doc/orm/getting_started.md)\n15. [model](doc/orm/model.md)\n16. [relation](doc/orm/relation.md)\n17. [validation](doc/orm/validation.md)\n18. [using](doc/orm/using.md)\n19. [relation using callback](doc/orm/cbrelation.md)\n\n## es module(ElasticSearch client)\n20. [getting started](doc/es/getting_started.md)\n21. [Entity - mapping es document](doc/es/Entity.md)\n22. [EsManager - manage es index](doc/es/EsManager.md)\n23. [EsDocRepository - as entity repository](doc/es/EsDocRepository.md)\n24. [EsQueryBuilder - query builder](doc/es/EsQueryBuilder.md)\n\n## other\n25. [deploy](doc/deploy.md)\n\n# 中文文档\n## http模块\n1. [快速开始](doc/http/getting_started.cn.md)\n2. [控制器](doc/http/controller.cn.md)\n3. [请求](doc/http/request.cn.md)\n4. [响应](doc/http/response.cn.md)\n5. [路由](doc/http/route.cn.md)\n6. [上传](doc/http/upload.cn.md)\n7. [请求处理流程](doc/http/flow.cn.md)\n8. [cookie](doc/http/cookie.cn.md)\n9. [会话](doc/http/session.cn.md)\n10. [jetty server](doc/http/jetty_server.cn.md)\n11. [生成api文档](doc/http/api_doc.cn.md)\n12. [整合jphp-支持php来写db/orm代码](doc/orm/jphp.cn.md)\n13. [整合jphp-支持php来写控制器代码](doc/http/jphp.cn.md)\n\n## db模块\n14. [快速开始](doc/db/getting_started.cn.md)\n15. [查询](doc/db/query.cn.md)\n16. [sql构建器](doc/db/query_builder.cn.md)\n17. [db表达式](doc/db/expr.cn.md)\n\n## orm模块\n18. [快速开始](doc/orm/getting_started.cn.md)\n19. [模型](doc/orm/model.cn.md)\n20. [关联关系](doc/orm/relation.cn.md)\n21. [校验](doc/orm/validation.cn.md)\n22. [使用](doc/orm/using.cn.md)\n23. [基于回调的关联关系](doc/orm/cbrelation.cn.md)\n\n## es模块(ElasticSearch client)\n24. [快速开始](doc/es/getting_started.md)\n25. [实体类 - 映射文档](doc/es/Entity.md)\n26. [EsManager - 管理es索引](doc/es/EsManager.md)\n27. [EsDocRepository - 实体仓库类](doc/es/EsDocRepository.md)\n28. [EsQueryBuilder - 查询构建器](doc/es/EsQueryBuilder.md)\n\n## 其他\n29. [部署](doc/deploy.cn.md)\n30. [changelog](doc/changelog.md)\n\n## jkorm/mybatis性能测试与对比\n31. [测试场景](doc/orm/benchmark/sence.md)\n32. [model代码](doc/orm/benchmark/code_model.md)\n33. [add场景代码](doc/orm/benchmark/code_add.md)\n34. [update场景代码](doc/orm/benchmark/code_update.md)\n35. [delete场景代码](doc/orm/benchmark/code_delete.md)\n36. [getDepWithEmps场景代码](doc/orm/benchmark/code_getDepWithEmps.md)\n37. [getEmpsByConditionIf场景代码](doc/orm/benchmark/code_getEmpsByConditionIf.md)\n38. [updateEmpOnDynFields场景代码](doc/orm/benchmark/code_updateEmpOnDynFields.md)\n39. [getEmpsByIds场景代码](doc/orm/benchmark/code_getEmpsByIds.md)\n40. [第1轮测试结果](doc/orm/benchmark/result_round1.md)\n41. [第2轮测试结果](doc/orm/benchmark/result_round2.md)\n\n# 其他\n[变更历史](doc/changelog.md)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshigebeyond%2Fjkmvc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshigebeyond%2Fjkmvc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshigebeyond%2Fjkmvc/lists"}