当前位置: 首页 > news >正文

跟我一起学“仓颉Web”基础编程-图书管理Demo

目录

一、数据库

二、图书管理Demo

三、小结


一、数据库

创建数据库

create database web_study; use web_study;

创建数据表

CREATE TABLE `book` ( `id` INT NOT NULL AUTO_INCREMENT COMMENT '图书id', `name` VARCHAR(20) NOT NULL COMMENT '图书名称', `author` VARCHAR(20) NOT NULL COMMENT '作者', `type` VARCHAR(10) NOT NULL COMMENT '图书分类', `price` DOUBLE NOT NULL COMMENT '图书价格', PRIMARY KEY (`id`) ) COMMENT='图书信息表';

给数据表添加数据

INSERT INTO book (id, name, author, type, price) VALUES (1, 'CangJie编程', '钝子生', '名著', 89.90), (2, 'MySQL必知必会', 'Ben Forta', '科幻', 39.80), (3, '计算机网络', '谢希仁', '小说', 49.90), (4, '数据结构与算法', '严蔚敏', '社科', 55.20), (5, '活着', '余华', '历史', 29.80), (6, '三体', '刘慈欣', '外国', 38.50), (7, '流浪地球', '刘慈欣', '科普', 25.90), (8, '红楼梦', '曹雪芹', '计算机', 52.00), (9, '西游记', '吴承恩', '数据库', 43.70), (10, '水浒传', '施耐庵', '网络', 40.20), (11, '三国演义', '罗贯中', '算法', 45.10), (12, '百年孤独', '马尔克斯', '文学', 56.80), (13, '老人与海', '海明威', '名著', 22.50), (14, '解忧杂货店', '东野圭吾', '科幻', 37.30), (15, '白夜行', '东野圭吾', '小说', 49.00), (16, '嫌疑人X的献身', '东野圭吾', '社科', 35.60), (17, '乡土中国', '费孝通', '历史', 28.40), (18, '人类简史', '尤瓦尔', '外国', 68.20), (19, '时间简史', '霍金', '科普', 48.90);

二、图书管理Demo

采用三层架构+MVC实现,在Src目录下,创建book目录以及分层目录,如图所示

entity包的book代码

package WebStudy.book.entity import std.convert.* // Book实体类 public class Book { // 主构造函数 public Book( private var _id: Int64, private var _name: String, private var _author: String, private var _type: String, private var _price: Float64, ){} // 无参构造函数 public init() { this._id = 0 this._name = '' this._author = '' this._type = '' this._price = 0.0 } // id public mut prop id: Int64 { get() { this._id } set(v) { this._id = v } } // 名称 public mut prop name: String { get() { this._name } set(v) { this._name = v } } // 作者 public mut prop author: String { get() { this._author } set(v) { this._author = v } } // 类别 public mut prop bookType: String { get() { this._type } set(v) { this._type = v } } // 价格 public mut prop price: String { get() { this._price.format('.2') } set(v) { this._price = Float64.parse(v) } } }

mapper包的book_mapper代码

package WebStudy.book.mapper import WebStudy.book.entity.* import std.collection.* import std.database.sql.* import std.convert.* import mariadb.cdbc.* /* * 图书数据访问层 */ public class BookMapper { // 获取数据库驱动 // return 数据资源 和 连接 private static func getDriver(): (Datasource, Connection) { // 创建驱动 let driver = DriverManager.getDriver('mariadb').getOrThrow() // 数据库的链接 let url = 'mariadb://127.0.0.1:3306' // 数据库用户 let username = ('username', 'root') // 数据库密码 let password = ('password', 'YGBG372S1') // 需要连接数据库 let database = ('database', 'web_study') // 启动驱动获取数据资源 let dataSource = driver.open(url, [username, password, database]) // 创建连接 let connection = dataSource.connect() return (dataSource, connection) } // 新增图书 // book 图书实体类 // return 数据库影响行数 public func addBook(book: Book): Int64 { let (dataSource, connection) = BookMapper.getDriver() let sql = 'insert into book (name, author, type, price) values (?,?,?,?)' let statement = connection.prepareStatement(sql) statement.set<String>(1, book.name) statement.set<String>(2, book.author) statement.set<String>(3, book.bookType) statement.set<Float64>(4, Float64.parse(book.price)) let updateResult = statement.update() let row = updateResult.rowCount // 释放资源 statement.close() connection.close() dataSource.close() return row } // 根据id删除图书 // id id // return 数据库影响行数 public func deleteBook(id: Int64): Int64 { let (dataSource, connection) = BookMapper.getDriver() let sql = 'delete from book where id=?' let statement = connection.prepareStatement(sql) statement.set<Int64>(1, id) let updateResult = statement.update() let row = updateResult.rowCount // 释放资源 statement.close() connection.close() dataSource.close() return row } // 更新图书 // book 图书实体类 // return 数据库影响行数 public func updateBook(book: Book): Int64 { let (dataSource, connection) = BookMapper.getDriver() let sql = 'update book set name=?, author=?, type=?, price=? where id=?' let statement = connection.prepareStatement(sql) statement.set<String>(1, book.name) statement.set<String>(2, book.author) statement.set<String>(3, book.bookType) statement.set<Float64>(4, Float64.parse(book.price)) statement.set<Int64>(5, book.id) let updateResult = statement.update() let row = updateResult.rowCount // 释放资源 statement.close() connection.close() dataSource.close() return row } // 根据id获取图书信息 // id id // return 图书信息 public func getBook(id: Int64): Book { let (dataSource, connection) = BookMapper.getDriver() let sql = 'select * from book where id=?' let statement = connection.prepareStatement(sql) statement.set<Int64>(1, id) let queryResult = statement.query() let book = Book() while (queryResult.next()) { book.id = queryResult.get<Int64>(1) book.name = queryResult.get<String>(2) book.author = queryResult.get<String>(3) book.bookType = queryResult.get<String>(4) book.price = queryResult.get<Float64>(5).toString() } // 释放资源 queryResult.close() statement.close() connection.close() dataSource.close() return book } // 分页查询图书列表 // page 当前页 // row 每页显示行数 // return 图书列表 public func getBookList(page: Int64, row: Int64): ArrayList<Book> { let (dataSource, connection) = BookMapper.getDriver() let sql = 'select * from book where id > ? order by id limit ?' let statement = connection.prepareStatement(sql) statement.set<Int64>(1, (page-1) * row) statement.set<Int64>(2, row) let queryResult = statement.query() let books = ArrayList<Book>() while (queryResult.next()) { let book = Book( queryResult.get<Int64>(1), queryResult.get<String>(2), queryResult.get<String>(3), queryResult.get<String>(4), queryResult.get<Float64>(5) ) books.add(book) } // 释放资源 queryResult.close() statement.close() connection.close() dataSource.close() return books } // 获取图书列表总数 public func getTotal(): Int64 { let (dataSource, connection) = BookMapper.getDriver() let sql = 'select COUNT(*) as total from book' let statement = connection.prepareStatement(sql) let queryResult = statement.query() var total = 0 while (queryResult.next()) { total = queryResult.get<Int64>(1) } // 释放资源 queryResult.close() statement.close() connection.close() dataSource.close() return total } }

service包的book_service代码

package WebStudy.book.service import WebStudy.book.entity.* import WebStudy.book.mapper.* import std.collection.* /* * 图书业务逻辑层 */ public class BookService { // 图书数据访问层 private let bookMapper = BookMapper() // 新增图书 // book 图书实体类 // return 数据库影响行数 public func addBook(book: Book): Int64 { return this.bookMapper.addBook(book) } // 根据id删除图书 // id id // return 数据库影响行数 public func deleteBook(id: Int64): Int64 { return this.bookMapper.deleteBook(id) } // 更新图书 // book 图书实体类 // return 数据库影响行数 public func updateBook(book: Book): Int64 { return this.bookMapper.updateBook(book) } // 根据id获取图书信息 // id id // return 图书信息 public func getBook(id: Int64): Book { return this.bookMapper.getBook(id) } // 分页查询图书列表 // page 当前页 // row 每页显示行数 // return 图书列表 public func getBookList(page: Int64, row: Int64): ArrayList<Book> { return this.bookMapper.getBookList(page, row) } // 获取图书列表总数 public func getTotal(): Int64 { return this.bookMapper.getTotal() } }

controller包的book_controller代码

package WebStudy.book.controller import WebStudy.book.entity.* import WebStudy.book.service.* import std.collection.* /* * 图书控制器 */ public class BookController { // 图书业务逻辑层 private let bookService = BookService() // 新增图书 // book 图书实体类 // return 数据库影响行数 public func addBook(book: Book): Int64 { return this.bookService.addBook(book) } // 根据id删除图书 // id id // return 数据库影响行数 public func deleteBook(id: Int64): Int64 { return this.bookService.deleteBook(id) } // 更新图书 // book 图书实体类 // return 数据库影响行数 public func updateBook(book: Book): Int64 { return this.bookService.updateBook(book) } // 根据id获取图书信息 // id id // return 图书信息 public func getBook(id: Int64): Book { return this.bookService.getBook(id) } // 分页查询图书列表 // page 当前页 // row 每页显示行数 // return 图书列表 public func getBookList(page: Int64, row: Int64): ArrayList<Book> { return this.bookService.getBookList(page, row) } // 图书列表页 public func bookListPage(page: Int64, row: Int64, books: ArrayList<Book>): String { let total = this.bookService.getTotal() // 计算总页数 var totalPage = if (total % row == 0) { total / row } else { total / row + 1 } var currentPage = page var bookListPage = """ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>图书列表</title> <style> table { width: 800px; margin: 20px auto; border-collapse: collapse; } th, td { border: 1px solid #333; padding: 8px; text-align: center; } th { background-color: #eee; } .btn { padding: 5px 10px; cursor: pointer; margin:0 3px; } .add-btn { margin: 20px auto; display: block; width: 120px; } .page { text-align: center; margin: 20px; font-size:16px; } </style> </head> <body> <h2 class="btn add-btn">图书列表</h2> <button class="btn add-btn" onclick="toAdd()">新增图书</button> <table> <thead> <tr> <th>ID</th> <th>图书名称</th> <th>作者</th> <th>类型</th> <th>价格</th> <th>操作</th> </tr> </thead> <tbody> """ // 循环渲染图书数据 for (book in books) { bookListPage += """ <tr> <td>${book.id}</td> <td>${book.name}</td> <td>${book.author}</td> <td>${book.bookType}</td> <td>${book.price}</td> <td> <button class="btn" onclick="toUpdate(${book.id})">修改</button> <button class="btn" onclick="deleteBook(${book.id})">删除</button> </td> </tr> """ } bookListPage += """ </tbody> </table> <div class="page"> <button class="btn" onclick="getList(1)">首页</button> <button class="btn" onclick="prevPage()" ${if (currentPage <= 1) {'disabled'} else {''} }>上一页</button> <span>第 ${currentPage} 页 / 共 ${totalPage} 页</span> <button class="btn" onclick="nextPage()" ${if (currentPage >= totalPage) {'disabled'} else {''} }>下一页</button> </div> <script> // 获取列表(跳转到指定页) function getList(pageNum) { // 这里替换成你真实的后端分页接口/路由 location.href = "/book/getList?page=" + pageNum + "&row=${row}"; } // 上一页 function prevPage() { if (${currentPage} > 1) { getList(${currentPage} - 1); } } // 下一页 function nextPage() { if (${currentPage} < ${totalPage}) { getList(${currentPage} + 1); } } // 新增页面 function toAdd() { location.href = "/book/add"; } // 修改页面 function toUpdate(id) { location.href = "/book/update?id=" + id; } // 删除图书 function deleteBook(id) { if (confirm("确定删除该图书吗?")) { location.href = "/book/delete?id=" + id + "&page=${currentPage}" + "&row=${row}"; } } </script> </body> </html> """ return bookListPage } // 新增图书页面 public func addBookPage(): String { return """ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>新增图书</title> <style> .form { width: 400px; margin: 50px auto; } .form div { margin: 15px 0; } label { display: inline-block; width: 80px; } input { width: 250px; padding: 5px; } .btn { padding: 8px 20px; margin: 10px 5px; cursor: pointer; } </style> </head> <body> <div class="form"> <h2>新增图书</h2> <form action="/book/doAdd" method="post"> <div> <label>图书名称:</label> <input type="text" name="name" required> </div> <div> <label>作者:</label> <input type="text" name="author" required> </div> <div> <label>类型:</label> <input type="text" name="bookType" required> </div> <div> <label>价格:</label> <input type="number" name="price" required> </div> <div> <input type="submit" value="提交" class="btn"> <button type="button" class="btn" onclick="back()">返回</button> </div> </form> </div> <script> // 返回列表 function back() { window.location.href = '/book/getList?page=1&row=10'; } </script> </body> </html> """ } // 修改图书页面 public func updateBookPage(book: Book): String { return """ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>修改图书</title> <style> .form { width: 400px; margin: 50px auto; } .form div { margin: 15px 0; } label { display: inline-block; width: 80px; } input { width: 250px; padding: 5px; } .btn { padding: 8px 20px; margin: 10px 5px; cursor: pointer; } </style> </head> <body> <div class="form"> <h2>修改图书</h2> <form action="/book/doUpdate" method="post"> <input type="hidden" name="id" id="bookId" value="${book.id}"> <div> <label>图书名称:</label> <input type="text" name="name" id="name" value="${book.name}" required> </div> <div> <label>作者:</label> <input type="text" name="author" id="author" value="${book.author}" required> </div> <div> <label>类型:</label> <input type="text" name="bookType" id="type" value="${book.bookType}" required> </div> <div> <label>价格:</label> <input type="text" name="price" id="price" value="${book.price}" required> </div> <div> <input type="submit" value="提交" class="btn"> <button type="button" class="btn" onclick="back()">返回</button> </div> </form> </div> <script> // 返回列表 function back() { window.location.href = '/book/getList?page=1&row=10'; } </script> </body> </html> """ } }

book包的server代码

package WebStudy.book import WebStudy.book.entity.* import WebStudy.book.controller.* import stdx.net.http.* import std.convert.* /* * 图书服务启动类 */ public class BookServer { // 图书控制器 private let bookController = BookController() // 图书列表 private func bookList(): FuncHandler { return FuncHandler { httpContext => let request = httpContext.request // 获取Form let form = request.form // 页数 let page = Int64.parse(form.get('page') ?? '') // 每页显示行数 let row = Int64.parse(form.get('row') ?? '') // 图书列表 let books = this.bookController.getBookList(page, row) httpContext.responseBuilder.header('Content-Type', 'text/html;charset=UTF-8') httpContext.responseBuilder.body(this.bookController.bookListPage(page, row, books)) } } // 新增图书页 private func addBook(): FuncHandler { return FuncHandler { httpContext => httpContext.responseBuilder.header('Content-Type', 'text/html;charset=UTF-8') httpContext.responseBuilder.body(this.bookController.addBookPage()) } } // 执行新增图书 private func doAddBook(): FuncHandler { return FuncHandler { httpContext => // 获取请求参数 let request = httpContext.request let form = request.form let book = Book() book.name = form.get('name') ?? '' book.author = form.get('author') ?? '' book.bookType = form.get('bookType') ?? '' book.price = form.get('price') ?? '' // 执行添加 let row = this.bookController.addBook(book) if (row >= 1) { // 重定向 httpContext.responseBuilder.status(302) httpContext.responseBuilder.header('Location', '/book/getList?page=1&row=10') } } } // 删除图书 private func deleteBook(): FuncHandler { return FuncHandler { httpContext => let request = httpContext.request // 获取Form let form = request.form // id let id = Int64.parse(form.get('id') ?? '') // 页数 let page = Int64.parse(form.get('page') ?? '') // 每页显示行数 let row = Int64.parse(form.get('row') ?? '') // 图书列表 let flag = this.bookController.deleteBook(id) if (flag >= 1) { // 重定向 httpContext.responseBuilder.status(302) httpContext.responseBuilder.header('Location', '/book/getList?page=${page}&row=${row}') } } } // 修改图书页 private func updateBook(): FuncHandler { return FuncHandler { httpContext => // 获取请求参数 let request = httpContext.request let form = request.form let id = Int64.parse(form.get('id') ?? '') let book = this.bookController.getBook(id) httpContext.responseBuilder.header('Content-Type', 'text/html;charset=UTF-8') httpContext.responseBuilder.body(this.bookController.updateBookPage(book)) } } // 执行修改图书 private func doUpdateBook(): FuncHandler { return FuncHandler { httpContext => let request = httpContext.request let form = request.form // 获取表单参数 let id = Int64.parse(form.get('id') ?? '') let name = form.get('name') ?? '' let author = form.get('author') ?? '' let bookType = form.get('bookType') ?? '' let price = Float64.parse(form.get('price') ?? '') // 构造修改后的图书对象 let book = Book(id, name, author, bookType, price) // 执行修改 let row = this.bookController.updateBook(book) if (row >= 1) { // 重定向 httpContext.responseBuilder.status(302) httpContext.responseBuilder.header('Location', '/book/getList?page=1&row=10') } } } // 启动服务 public func startServer(): Unit { let server: Server = ServerBuilder().addr('127.0.0.1').port(8080).build() server.distributor.register('/book/getList', this.bookList()) server.distributor.register('/book/add', this.addBook()) server.distributor.register('/book/doAdd', this.doAddBook()) server.distributor.register('/book/delete', this.deleteBook()) server.distributor.register('/book/update', this.updateBook()) server.distributor.register('/book/doUpdate', this.doUpdateBook()) println('Web服务已启动...') println('http://localhost:8080/book/getList?page=1&row=10') server.serve() } }

主文件main代码

package WebStudy import WebStudy.book.BookServer main() { BookServer().startServer() }

运行结果

图书列表

新增

修改

删除

三、小结

本章为大家详细的介绍了仓颉Web开发实现图书管理Demo的内容。最后,创作不易,如果大家觉得我的文章对学习仓颉Web基础编程有帮助的话,就动动小手,点个免费的赞吧!收到的赞越多,我的创作动力也会越大哦,谢谢大家🌹🌹🌹!!!

http://www.cnnetsun.cn/news/2802420.html

相关文章:

  • 从笛卡尔到‘玩偶屋研究’:程序员如何用哲学思维提升技术文档写作?
  • Volga特征服务在EKS上的延迟压测与可扩展性实战
  • 从Jupyter到Kubernetes:机器学习模型服务化落地全链路
  • 深入DPDK l3fwd源码:手把手教你修改默认路由规则,定制自己的转发逻辑
  • Element UI弹窗实战:从‘顶部弹出’到‘优雅居中’,一个属性+一段CSS的完整改造流程
  • 告别开关!用Arduino Uno和APDS9930手势传感器做个挥手控灯(附完整代码与接线图)
  • 别再死记硬背switch了!通过‘简单计算器’案例,聊聊C++条件分支的选择策略与代码可读性
  • Wagmi 前端 Web3 库底层原理:基于 Viem 的钱包连接、Provider 单例管理与以太坊交易状态链路追踪
  • 【OpenClaw Skill 功能全解】,从文档处理到系统运维一站式(包含安装包)
  • 超越传统玻璃:元表面透镜 (Metalens) 如何重塑光学未来?
  • 别再让MinIO图片变下载!手把手教你用S3 Browser配置预览(附Java代码)
  • Roblox Studio新手避坑指南:从界面布局到资源上传,一次讲清那些没人告诉你的细节
  • 随机邻居嵌入
  • 深入CN3905规格书:除了Pin to Pin替代,它的低EMI和打嗝模式保护到底怎么用?
  • 机器学习模型生产化落地:从Jupyter到高可用服务的实战体系
  • 不止于升级:用HC32F460的Bootloader实现参数存储与固件下载的完整方案
  • 别再让模型‘偏科’了:用PyTorch实战搞定长尾数据分类(以CIFAR-100-LT为例)
  • 对话失败不是Bug,是用户认知的X光片
  • ACE框架:临床AI如何实现自主时序推理与动态知识进化
  • 不止是玩具:用Roblox Studio资源管理器高效管理你的游戏素材(图片、音频、模型全攻略)
  • 多标签分类本质:标签共现建模与评估体系重构
  • Halcon模板匹配实战:如何把辛苦训练的模型存下来,下次直接用?
  • Mythos:首个实现自主攻防闭环的AI漏洞挖掘模型
  • 2026年Java工程师必修:Spring Boot生产级能力全景图
  • 多维聚合实战:用Python构建可钻取数据立方体
  • SAP ABAP小技巧:用ALSM_EXCEL_TO_INTERNAL_TABLE函数实现SM30数据导入(含完整代码)
  • 本地大模型对话系统:CPU离线运行的轻量级LLaMA-GPT4All实战指南
  • 告别手动转存!用LabVIEW报表工具包直接读写.xlsx文件(支持中文)
  • 【紧急预警】CSDN AI选题功能开放行业词自定义!但92%运营人忽略这3个合规阈值与2个审核熔断点
  • STM32F103用USART3+TPIC1021实现LIN主节点通信(19200bps带CRC)