java实战——图书管理项目_java项目实战,零基础入门到精通,收藏这篇就够了

值得收藏的一些Java实战项目分享 今天来给大家分享几个值得作为Java新手收藏实战的项目 阅读详情
文章目录
  • 项目所需要的技术栈
  • 项目演示
  • 项目准备工作
    • 环境准备
    • 数据库数据准备
  • 前后端交互分析(前端代码我们使用现成)
  • 图书列表界面的创建
    • 查看前端发送的请求
    • 根据前端接收的返回值来编写model层
    • 根据请求编写controller层
    • 根据controller编写Service
    • 根据Service编写Mapper层
  • 添加图书
  • 前端
    • 后端Controller
    • Service
    • Mapper
  • 修改书籍信息
  • 批量删除
  • 结尾

项目所需要的技术栈

该项目是一个针对于SpringBoot+Mybatis+SpringMVC的基础运用项目适合初学者来检验水平测试能力,该项目所需技术栈如下

  • SpringBoot:作为项目的框架,使用Maven托管代码
  • Mybatis:使用Mybatis框架操纵数据库,其中使用了xml和注解两种方式去操作数据库
  • 前端ajax:前后端的交互使用的是ajax作为前端为后端发送数据以及接收数据
  • 使用的其他依赖:除此之外还使用了email的工具包来编写了注册页面在pom.xml文件中需要导入特定的依赖
  • 项目分层:项目分为前端页面+control(与前端建立连接的控制层)+Service(服务层供control层进行调用)+Mapper(操纵数据库实现数据与后端代码的 交互)+Model(需要实现的主类)。

项目演示

csdnBook

项目准备工作

首先项目准备层我们需要先确定好自己项目的大致框架也就是分为了多少个package,这些package之间的关系是怎么样的以及,是否要导入其他的依赖,以及建立好后端和数据库的连接等。那么首先我们先从创建一个SpringBoot项目开始

环境准备

创建项目的过程我们要先选好我们项目的路径,环境,spring版本,jdk的版本等。环境如下
在这里插入图片描述

首先我们得项目环境如图中所示首先Name和location是自己准备,然后语言我们使用java语言项目代码托管使用Maven,JDK版本使用17,java版本同上也是17版本。之后点击Next。
在这里插入图片描述
在这里我们需要配置好我们的项目所需要使用的依赖有哪些,以及我们Spring版本,我们的Spring版本使用3.2.6,然后我们的工具选择如下
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这些环境准备好之后我们就可以点击create了。
代码分层各个层的package创建如下
在这里插入图片描述
后端环境准备好之后我们就要来准备一下数据库了

数据库数据准备

在这里插入图片描述
我们数据库的名称就叫book_test我们数据库的建表语句如下首先是user_info管理登录用户

CREATE TABLE `user_info` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(128) NOT NULL,
  `password` varchar(128) NOT NULL,
  `delete_flag` tinyint(4) DEFAULT '0',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_name_UNIQUE` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='用户表'

其次是我们的图书表管理各种图书图书表建表语句如下

CREATE TABLE `book_info` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `book_name` varchar(127) NOT NULL,
  `author` varchar(127) NOT NULL,
  `count` int(11) NOT NULL,
  `price` decimal(7,2) NOT NULL,
  `publish` varchar(256) NOT NULL,
  `status` tinyint(4) DEFAULT '1' COMMENT '0-⽆效, 1-正常, 2-不允许借阅',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=81 DEFAULT CHARSET=utf8mb4

前后端交互分析(前端代码我们使用现成)

然后我们开始进行我们前后端交互的准备,其实也就是前端代码应当如何跟后端代码进行交互这里我们从第一个页面的login开始

 <div class="container-login">
        <div class="container-pic">
            <img src="pic/computer.png" width="350px">
        </div>
        <div class="login-dialog">
            <h3>登陆</h3>
            <div class="row">
                <span>用户名</span>
                <input type="text" name="userName" id="userName" class="form-control">
            </div>
            <div class="row">
                <span>密码</span>
                <input type="password" name="password" id="password" class="form-control">
            </div>
            <div class="row">
                <button type="button" class="btn btn-info btn-lg" onclick="login()">登录</button>
            </div>
            <div class="row">
                <button type="button" class="btn btn-info btn-lg" onclick="sign_in()">注册</button>
            </div>
        </div>

这里我们发现有个登录按钮那么我们应该先看看这个登录按钮是如何提交数据的。这里我们可以看出来当我们点击这个登录按钮之后,那么就会执行function login这个函数,这个函数其实就是通过ajax向后端发送请求的函数,他发送的数据包括,我们输入的用户名,我们输入的密码这些那么ajax的代码如下

function login() {
            // var userName=  $("#userName").val();
            // var password = $("#password").val()
            $.ajax({
                url: "/user/login",
                type: "post",
                data:{
                    userName: $("#userName").val(),
                    password: $("#password").val()
                },
                success:function(result){
                    if(result.code=="SUCCESS" && result.data ==""){
                        //密码正确
                        location.href = "book_list.html?pageNum=1";
                    }else{
                        alert(result.errMsg);
                    }
                    //返回fail 如何处理?
                    //返回一个统一的错误界面
                }
            });
        }

这里我们可以看到前端login交互代码中我们的ajax中的内容发送是将输入框中的用户名和密码发送进入,并且按照我们的url现实的是user和login那么我们就可以知道我们后端代码关于这部分地方该怎么来处理了。

  1. 首先我们要有相应的类去接收这部分提交的数据那么结合前端和数据库的设计来看我们的这个用户信息类需要有以下这些信息
    (1). 用户名称
    (2). 用户密码
    (3). 删除标志
    (4). 创建时间
    (5). 修改时间
    (6). 用户ID

那么按照上面的分层约定我们的用户信息类应该处于Model层那么代码如下

package com.example.mybooksystem.Model;

import lombok.Data;

import java.util.Date;
@Data
public class UserInfo {
    private Integer id;
    private String userName;
    private String password;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}

那么我们的controller层的路径也应该跟前端的url路径保持一致我们的controller的初始框架其实也就确定了下来如下

package com.example.mybooksystem.Controller;
import com.example.mybooksystem.Model.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/user")
@RestController
public class UserControl {
    @RequestMapping("/login")
    public void login(UserInfo userInfo){
       /*详细代码
       */
    }
}

此外我们还需要添加一些工具类比如说我们看到前端代码在收到后端代码返回值的那部分,
在这里插入图片描述
也就是这一部分,我们发现我们后端的返回值既需要包含一个空字符串,也需要包含一个状态码为SUCCESS的状态表示,因此我们需要一个Result工具类对我们返回结果做包装,此外还需要创建一个状态码类来表示我们返回的状态码。那么这部分工具类的实现其实我们可以使用,一个enum进行那么首先我们要先创建一个Enums的package然后把我们的类写进去。
在这里插入图片描述

package com.example.mybooksystem.Enums;
import lombok.Data;
public enum ResultStatus {
    SUCCESS(200),
    FAIL(-1),
    NOLOGIN(-2);
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
    private int code;
    ResultStatus(int code){
        this.code=code;
    }
}

有了这个状态码代码后我们还需要创建一个对结果进行包装的Result类它的实现我们可以放在model层那么代码如下

package com.example.mybooksystem.Model;

import com.example.mybooksystem.Enums.ResultStatus;
import lombok.Data;

@Data
public class Result<T> {
    private T data;
    private ResultStatus code;
    private String errMsg;
    public static <T>Result success(T data){
        Result result=new Result<>();
        result.setData(data);
        result.setCode(ResultStatus.SUCCESS);
        return result;
    }
    public static <T>Result Fail(T data){
        Result result=new Result<>();
        result.setData(data);
        result.setCode(ResultStatus.FAIL);
        return result;
    }
    public static <T>Result Nologin(T data){
        Result result=new Result<>();
        result.setData(data);
        result.setCode(ResultStatus.NOLOGIN);
        return result;
    }
}


然后接下来我们要对这个login进行数据的对比,也就是查看前端发送来的数据和我们数据库中的数据是否一致,那么这部分的代码应该怎么写呢?这里我们需要先对我们的数据库进行配置,配置文件就是yml。内容如下

spring:
  application:
  name: MyBookSystem
  # ???????
  datasource:
    url: jdbc:mysql://127.0.0.1:3308/book_test?characterEncoding=utf8&useSSL=false #这里也是自己配置的写
    username: #连接数据库的用户名称
    password: #连接数据库使用的密码
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
  configuration:
    map-underscore-to-camel-case: true #????????
  mapper-locations: classpath:mybatis/*Mapper.xml #数据库xml文件的扫描路径
logging:
  file:
    name: spring-book.log
server:
  port: 9090

那么接下来我们按照分层来写的Controller层调用的就是Service层,然后Service层调用的是Mapper层,Mapper层负责去数据库里面拿数据,因此我们先从Mapper层来写那么mapper层其实就是绑定了响应的xml文件因此我们还需要一个xml文件来写我们的sql代码那么如下就是了

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mybooksystem2.Mapper.UserInfoMapper">
    <select id="SelectByName" resultType="com.example.mybooksystem2.Model.UserInfo">
        select * from user_info where user_name=#{userName} --绑定我们的mapper类中的方法
    </select>
</mapper>


Mapper

package com.example.mybooksystem2.Mapper;

import com.example.mybooksystem2.Model.UserInfo;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserInfoMapper {
    UserInfo SelectByName(String userName);
}



Service

package com.example.mybooksystem2.Service;
import com.example.mybooksystem2.Mapper.UserInfoMapper;
import com.example.mybooksystem2.Model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
    @Autowired
    UserInfoMapper userInfoMapper;
    public UserInfo SelectByName(UserInfo userInfo){
        return userInfoMapper.SelectByName(userInfo.getUserName());
    }
}


Controller

package com.example.mybooksystem2.Controller;

import com.example.mybooksystem2.Enums.ResultStatus;
import com.example.mybooksystem2.Model.*;
import com.example.mybooksystem2.Service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    UserService userService;
    @RequestMapping("/login")
    public com.example.mybooksystem2.Model.Result<String> login(com.example.mybooksystem2.Model.UserInfo userInfo){
        com.example.mybooksystem2.Model.Result<String> result=new com.example.mybooksystem2.Model.Result<>();
        if(userInfo==null){
            result.setData("");
            result.setCode(ResultStatus.FAIL);
            System.out.println("未收到登录信息");
            result.setErrMsg("未收到登录信息");
            return  result;
        }
        if(userInfo.getUserName()==null||userInfo.getPassword()==null){
            result.setData("");
            result.setCode(ResultStatus.FAIL);
            System.out.println("未收到登录信息");
            result.setErrMsg("未收到登录信息");
            return  result;
        }
        com.example.mybooksystem2.Model.UserInfo userInfo1=userService.SelectByName(userInfo);
        if(userInfo1==null){
            result.setCode(ResultStatus.FAIL);
            result.setData("");
            System.out.println("用户名或者密码错误");
            return  result;
        }
        if(userInfo1.getPassword().equals(userInfo.getPassword())){
            result.setCode(ResultStatus.SUCCESS);
            result.setData("");
            System.out.println("成功登录");
            return  result;
        }
        return result;
    }
}


到这里登录界面就是搞定了那么接下来该实现最复杂的图书列表界面了

图书列表界面的创建

查看前端发送的请求

$.ajax({
                url: "/book/getBookListByPage" + location.search,
                type: "get",
                success: function (result) {
                    //前端需要做更多的判断, 课堂不过多扩展
                    // if (result.code == "NOLOGIN") { //用户未登录
                    //     location.href = "login.html";
                    // }

                    if (result.data != null && result.data.records != null) {
                        var finnalHtml = "";
                        for (var book of result.data.records) {
                            finnalHtml += '<tr>';
                            finnalHtml += '<td><input type="checkbox" name="selectBook" value="' + book.id + '" id="selectBook" class="book-select"></td>';
                            finnalHtml += '<td>' + book.id + '</td>';
                            finnalHtml += '<td>' + book.bookName + '</td>';
                            finnalHtml += '<td>' + book.author + '</td>';
                            finnalHtml += '<td>' + book.count + '</td>';
                            finnalHtml += '<td>' + book.price + '</td>';
                            finnalHtml += '<td>' + book.publish + '</td>';
                            finnalHtml += '<td>' + book.statusCN + '</td>';
                            finnalHtml += '<td>';
                            finnalHtml += '<div class="op">';
                            finnalHtml += '<a href="book_update.html?bookId=' + book.id + '">修改</a>';
                            finnalHtml += '<a href="javascript:void(0)" οnclick="deleteBook(' + book.id + ')">删除</a>';
                            finnalHtml += '</div></td></tr>';
                        }
                        $("tbody").html(finnalHtml);

                        var data = result.data;
                        //翻页信息
                        $("#pageContainer").jqPaginator({
                            totalCounts: data.count, //总记录数
                            pageSize: 10,    //每页的个数
                            visiblePages: 5, //可视页数
                            currentPage: data.pageRequest.pageNum,  //当前页码
                            first: '<li class="page-item"><a class="page-link">首页</a></li>',
                            prev: '<li class="page-item"><a class="page-link" href="javascript:void(0);">上一页<\/a><\/li>',
                            next: '<li class="page-item"><a class="page-link" href="javascript:void(0);">下一页<\/a><\/li>',
                            last: '<li class="page-item"><a class="page-link" href="javascript:void(0);">最后一页<\/a><\/li>',
                            page: '<li class="page-item"><a class="page-link" href="javascript:void(0);">{{page}}<\/a><\/li>',
                            //页面初始化和页码点击时都会执行
                            onPageChange: function (page, type) {
                                console.log("第" + page + "页, 类型:" + type);
                                if (type == "change") {
                                    location.href = "book_list.html?pageNum=" + page;
                                }
                            }
                        });
                    }

                },
                error: function (error) {
                    console.log(error);
                    if (error != null && error.status == 401) {
                        location.href = "login.html";
                    }
                }
            });

在这里我们得到了我们的前端url是getBookListByPage然后根据返回信息我们可以知道,我们需要返回的信息有哪些,那么接下来就需要到我们的model层进行实现了

根据前端接收的返回值来编写model层

首先我们需要有图书的信息//BookInfo

package com.example.mybooksystem2.Model;

import lombok.Data;

import java.math.BigDecimal;
import java.util.Date;
@Data
public class BookInfo {
    private Integer id;
    private String bookName;
    private String author;
    private Integer count;
    private BigDecimal price;
    private String publish;
    private Integer status; //1-正常   2-不可借阅
    private String statusCN;
    private Date createTime;
    private Date updateTime;
}

其次我们需要有每页要显示多少条数据那么我们需要一个接收请求的类因为前端给我们发送的数据其实是一个这一页要的数据是从多少到多少的那种格式因此我们也需要按照这个格式去接收请求

package com.example.mybooksystem2.Model;
import lombok.Data;
@Data
public class PageRequest {
    private Integer pageNum=1;
    private Integer pageSize=10;
    private Integer offSet;
    public Integer getOffSet(){
        return (pageNum-1)*pageSize;
    }
}

然后我们还需要处理返回值因此我们需要对返回值进行处理的类也就是PageResult

package com.example.mybooksystem2.Model;
import com.example.mybooksystem2.Model.PageRequest;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class PageResult<T> {
    private List<T> records;
    private Integer count;
    private PageRequest pageRequest;
}

然后根据项目演示中我们发现我们需要将状态码转换为字符串因此我们后端可以直接进行转换方法就是制作一个enum即可

package com.example.mybooksystem2.Enums;
public enum BookStatus {
    DELETE(0,"删除"),
    NORMAL(1,"可借阅"),
    FORBIDDEN(2,"不可借阅"),
    ;
    private Integer code;
    BookStatus(Integer code,String desc){
        this.code=code;
        this.desc=desc;
    }
    public Integer getCode() {
        return code;
    }
    public static BookStatus getDescBycode(Integer code){
        switch (code){
            case 0: return DELETE;
            case 1: return NORMAL;
            case 2:
            default:
                return FORBIDDEN;
        }
    }
    public void setCode(Integer code) {
        this.code = code;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    private String desc;
}

根据请求编写controller层

然后根据上面实现的类我们可以编写出controller的代码首先我们获得的是,PageRequest,其次我们返回的是一个Result,然后这个Result中包含的是一个PageResult,听到这里有很多人可能头有些大?这是什么?我给大家解读以下请看下面的这个代码

@RestController
@RequestMapping("/book")
public class BookController {
    @Autowired
    BookService bookService;
    @RequestMapping("/getBookListByPage")
    public Result<PageResult<BookInfo>> getBookListByPage(PageRequest pageRequest){
        PageResult<BookInfo>bookInfoPageResult=bookService.selectBookByPage(pageRequest);
        return Result.success(bookInfoPageResult);
    }
}

请结合前端一起看一下这个代码,前端中我们需要判断是否success,因此我们的返回值必须有个字段时success可是这样一看的话我们就需要Result,这里我们注意Result是一个模板类,因此我们可以进行套娃,首先先讨一个PageResult这样就可以使得我们的返回值可以显示这个图书的状态,Result可以显示我们后端是否执行成功,只用BookInfo就可以展示每本图书的信息了。

根据controller编写Service

那么接下来就要你根据上面的controller我们看一下项目演示图片
在这里插入图片描述
我们发现我们包含的元素,有一个状态这个状态时一个字符串的形式表现出来的,但是Controller层我们可以看到他时负责和前端交互然后把数据返回的,也就是说这里的数据处理需要依靠Service层来进行才可以那么Service该如何进行呢?代码如下

@Service
public class BookService {
    @Autowired
    BookInfoMapper bookInfoMapper;
    public PageResult<BookInfo>selectBookByPage(PageRequest pageRequest){
        List<BookInfo>bookInfos=bookInfoMapper.QueryBookByPage(pageRequest.getOffSet(),pageRequest.getPageSize());
        for(BookInfo bookInfo:bookInfos){
            bookInfo.setStatusCN(BookStatus.getDescBycode(bookInfo.getStatus()).getDesc());
        }
        return new PageResult<>(bookInfos,count,pageRequest);
    }
}

这里大部分代码应该都是可以理解的,我给捋一下,首先就是service代码调用mapper代码,maper的内部其实使用的时select的limit查询从而使得我们可以获取到某一页的数据。然后当我们获取到数据后这个数据保存在我们设置的List < BookInfo>中,接下来就是到了最难懂的一步,我们可以看到我们在显示的时候显示的状态是一个String字符串,可是我们的BookInfo 在数据库中为了存储方便使用的是一个整数,因此这个该怎么办呢?这时候我们就用到了我们的BookInfo中的另一个参数
在这里插入图片描述
也就是statusCN这个变量是一个String类型他保存的就是从status转换来的字符串,当然了如果我们使用if判断的形式那太麻烦了因此我们设置的有一个类那就是我们的BookStatus在这里面我们有一个方法
**getDescBycode()**我们来看一下这个方法的代码如下

    public static BookStatus getDescBycode(Integer code){
        switch (code){
            case 0: return DELETE;
            case 1: return NORMAL;
            case 2:
            default:
                return FORBIDDEN;
        }
    }

在这里插入图片描述
我们结合上面两个部分来看我们可以得出它可以返回一个BookStatus对象这个对象包含的有各种数字代表的是哪种状态然后我们再调用BookStatus中的getDesc()方法就可以得出我们的这本书是一个什么状态了。

根据Service编写Mapper层

那么有了上面Service层的介绍我想大家也能猜到Mapper层是什么了,他就是一个limit查询代码如下

    @Select("select * from book_info where status!=0 order by id asc limit #{offset},#{limit}")
    List<BookInfo>QueryBookByPage(Integer offset,Integer limit);

添加图书

然后接下来我们来实现添加图书有了上面的经验这里其实我们就很简单了
在这里插入图片描述

前端

首先依旧是第一步结合前端推后端

      function add() {
            $.ajax({
                url: "/book/addBook",
                type: "post",
                data: $("#addBook").serialize(),
                success: function (result) {
                    if (result.code == "SUCCESS" && result.data == "") {
                        //添加成功
                        location.href = "book_list.html";
                    } else {
                        alert(result.data);
                    }
                }, 
                error: function (error) {
                    //用户未登录
                    if (error != null && error.status == 401) {
                        location.href = "login.html";
                    }
                }
            });
        }

首先通过前端我们可以得到下面这些信息,首先我们的url是addBook,其次我们的数据其实就是表格中输入的数据那么有了这些加上上面的基础那么你的想法是什么呢?
反正我的第一想法就是利用BookInfo接收到前端获取到的信息,然后调用Service,Service调用Mapper然后使用一个insert语句将这个记录插入进去。然后我们再来看一下它的返回值,我们可以看到它的返回值依然是一个SUCCESS+一个空字符串那就好写了我们直接上代码

后端Controller

    @RequestMapping("/addBook")
    public Result<String>addBook(BookInfo bookInfo){
        Integer n= bookService.addBook(bookInfo);
        Result<String>result=new Result<>();
        if(n<=0){
            result.setCode(ResultStatus.FAIL);
            result.setData("失败");
            return result;
        }if(n==1){
            result.setData("");
            result.setCode(ResultStatus.SUCCESS);
            return result;
        }
        return result;
    }

这里首先后端调用Service根据Service的返回值进行判断,插入是否成功

Service

Service层调用Mapper层来更改数据库

    public Integer addBook(BookInfo bookInfo){
        Integer n=bookInfoMapper.addBook(bookInfo);
        return n;
    }

Mapper

然后mapper层写出接口,再有xml文件绑定这个接口方法进行sql代码的实现。

    Integer addBook(BookInfo bookInfo);

        <insert id="addBook">
            insert into book_info (book_name,author,`count`,`price`,publish)values (#{bookName},#{author},#{count},#{price},#{publish})
        </insert>

经过上面的步骤我们的图书就添加进去了。

修改书籍信息

修改书籍信息分为两步我们从前端页面来进行介绍
在这里插入图片描述
首先当我们点击修改之后会跳转到updata.html,
在这里插入图片描述
此时我们的界面中会显示原有的图书信息,那么此时我们的图书信息该怎么获取呢?很明显在更改操作开始前先进行了一个查找工作,那么既然如此我们需要先实现一个接口也就是queryBookById,那么按照我们的代码逻辑,首先controller层实现接口调用Service层,Service层调用Mapper层我们来看一下
Mapper层

    @Select("select * from book_info where id=#{id}")
    BookInfo queryBookById(Integer id);

Service层

   public BookInfo queryBookById(Integer id){
        return bookInfoMapper.queryBookById(id);
    }

controller层

    @RequestMapping("/queryBookById")
    public Result<BookInfo>queryBookById(Integer bookId){
        BookInfo bookInfo=bookService.queryBookById(bookId);
        return Result.success(bookInfo);
    }

然后我们继续实现updata这里比较困难的地方就是有时候我们更改可能只更改名称其余的字段可能是空因此我们需要在xml编写sql代码

        <update id="updateBook">
            update book_info
            <set>
                <if test="bookName!=null">
                    book_name=#{bookName},
                </if>

                <if test="author!=null">
                    author=#{author},
                </if>

                <if test="count!=null">
                    `count` =#{count},
                </if>
                <if test="price!=null">
                    price=#{price},
                </if>
                <if test="publish!=null">
                    publish=#{publish},
                </if>
                <if test="status!=null">
                    status=#{status}
                </if>
            </set>
            where id=#{id}
        </update>

那么有了Mapper层的xml代码之后我们其他的代码就很容易实现了。

批量删除

批量删除是怎么样的呢?其实批量删除就是传入一个数组这个数组里面的元素是你要删除的bookId
那么我们用到的Sql语句是怎么样的呢我们来看一下xml中的代码即可首先我们要先知道book_info使用的是什么删除我们在未来工作中一般都是使用逻辑删除,也就是说这个数据并不是真的被删除了而是被逻辑删除了,如何逻辑删除就是使用一个status字段,用它来标记即可sql代码如下
XML代码

        <delete id="batchDeleteBook">
            update book_info set status=0
            where id in 
            <foreach collection="ids" open="(" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </delete>

这里我使用了foreach构造出了一个序列。


Mapper代码

 Integer batchDeleteBook(List<Integer>ids);


Service代码

    public Integer batchDeleteBook(List<Integer>ids){
        return bookInfoMapper.batchDeleteBook(ids);
    }


Controller代码

    @RequestMapping("/batchDeleteBook")
    public Result<String>batchDeleteBook(@RequestParam List<Integer>ids){
        Integer n=bookService.batchDeleteBook(ids);
        if(n==ids.size()){
            return Result.success("");
        }else{
            return Result.Fail("");
        }
    }

结尾

这里代码主体已经完成如果有感兴趣的人可以访问我的github或者gittee获取前端代码以及获取我更新了的后端代码
gitee连接
github连接

Java开发的就业市场正在经历结构性调整,竞争日益激烈

传统纯业务开发岗位(如仅完成增删改查业务的后端工程师)的需求,特别是入门级岗位,正显著萎缩。随着企业技术需求升级,市场对Java人才的要求已从通用技能转向了更深入的领域经验(如云原生、微服务)或前沿的AI集成能力。这也导致岗位竞争加剧,在一、二线城市,求职者不仅面临技术内卷,还需应对学历与项目经验的高门槛。

大模型为核心的AI领域正展现出前所未有的就业热度与人才红利

2025年,AI相关新发岗位数量同比激增543%,单月增幅最高超过11倍,大模型算法工程师位居热门岗位前列。行业顶尖人才的供需严重失衡,议价能力极强,跳槽薪资涨幅可达30%-50%。值得注意的是,市场并非单纯青睐算法研究员,而是急需能将大模型能力落地于复杂业务系统的工程人才。这使得具备企业级架构思维和复杂系统整合经验的Java工程师,在向“Java+大模型”复合人才转型时拥有独特优势,成为企业竞相争夺的对象,其薪资天花板也远高于传统Java岗位。

在这里插入图片描述

说真的,这两年看着身边一个个搞Java、C++、前端、数据、架构的开始卷大模型,挺唏嘘的。大家最开始都是写接口、搞Spring Boot、连数据库、配Redis,稳稳当当过日子。

结果GPT、DeepSeek火了之后,整条线上的人都开始有点慌了,大家都在想:“我是不是要学大模型,不然这饭碗还能保多久?”

先给出最直接的答案:一定要把现有的技术和大模型结合起来,而不是抛弃你们现有技术!掌握AI能力的Java工程师比纯Java岗要吃香的多。

即使现在裁员、降薪、团队解散的比比皆是……但后续的趋势一定是AI应用落地!大模型方向才是实现职业升级、提升薪资待遇的绝佳机遇!

如何学习AGI大模型?

作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

2025最新版优快云大礼包:《AGI大模型学习资源包》免费分享**

一、2025最新大模型学习路线

一个明确的学习路线可以帮助新人了解从哪里开始,按照什么顺序学习,以及需要掌握哪些知识点。大模型领域涉及的知识点非常广泛,没有明确的学习路线可能会导致新人感到迷茫,不知道应该专注于哪些内容。

我们把学习路线分成L1到L4四个阶段,一步步带你从入门到进阶,从理论到实战。

L1级别:AI大模型时代的华丽登场

L1阶段:我们会去了解大模型的基础知识,以及大模型在各个行业的应用和分析;学习理解大模型的核心原理,关键技术,以及大模型应用场景;通过理论原理结合多个项目实战,从提示工程基础到提示工程进阶,掌握Prompt提示工程。

L2级别:AI大模型RAG应用开发工程

L2阶段是我们的AI大模型RAG应用开发工程,我们会去学习RAG检索增强生成:包括Naive RAG、Advanced-RAG以及RAG性能评估,还有GraphRAG在内的多个RAG热门项目的分析。

L3级别:大模型Agent应用架构进阶实践

L3阶段:大模型Agent应用架构进阶实现,我们会去学习LangChain、 LIamaIndex框架,也会学习到AutoGPT、 MetaGPT等多Agent系统,打造我们自己的Agent智能体;同时还可以学习到包括Coze、Dify在内的可视化工具的使用。

L4级别:大模型微调与私有化部署

L4阶段:大模型的微调和私有化部署,我们会更加深入的探讨Transformer架构,学习大模型的微调技术,利用DeepSpeed、Lamam Factory等工具快速进行模型微调;并通过Ollama、vLLM等推理部署框架,实现模型的快速部署。

整个大模型学习路线L1主要是对大模型的理论基础、生态以及提示词他的一个学习掌握;而L3 L4更多的是通过项目实战来掌握大模型的应用开发,针对以上大模型的学习路线我们也整理了对应的学习视频教程,和配套的学习资料。

二、大模型经典PDF书籍

书籍和学习文档资料是学习大模型过程中必不可少的,我们精选了一系列深入探讨大模型技术的书籍和学习文档,它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础。(书籍含电子版PDF)

三、大模型视频教程

对于很多自学或者没有基础的同学来说,书籍这些纯文字类的学习教材会觉得比较晦涩难以理解,因此,我们提供了丰富的大模型视频教程,以动态、形象的方式展示技术概念,帮助你更快、更轻松地掌握核心知识。

四、大模型项目实战

学以致用 ,当你的理论知识积累到一定程度,就需要通过项目实战,在实际操作中检验和巩固你所学到的知识,同时为你找工作和职业发展打下坚实的基础。

五、大模型面试题

面试不仅是技术的较量,更需要充分的准备。

在你已经掌握了大模型技术之后,就需要开始准备面试,我们将提供精心整理的大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。


因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

2025最新版优快云大礼包:《AGI大模型学习资源包》免费分享

java项目开发实战案例 java项目开发实战,主要以案例讲解各种系统开发的流程,包括数据库,以及前台和后台之间的连接,主要以代码讲解为主。 立即下载

相关推荐

50个java编写的实战项目

这里是50个java编写的实战项目,很适合想加强自己能力的人学习的,毕竟学习之后还是靠实践,这个真的很有用的,可以按需所求来寻找合适自己的项目去做。

Java项目实战【超级详细】

java暑期自学后端

weixin_51673920的博客 1万+

Win11/Win10系统下,Proe5.0 M280终极版保姆级安装与激活指南(含SSQ补丁避坑)

本文提供Win11/Win10系统下Pro/E 5.0 M280终极版的详细安装与激活指南,涵盖环境配置、SSQ补丁应用及常见问题解决方案。通过系统调整、分步安装和性能优化,确保软件在现代操作系统上的稳定运行,特别适合机械设计用户参考。

weixin_30895059的博客 444

2023全新开源十个Java实战项目-可上手企业

代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载。部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。用户管理:用户是系统操作者,该功能主要完成系统用户配置。菜单管理:配置系统菜单,操作权限,按钮权限标识等。缓存监控:对系统的缓存查询,删除、清空等操作。

Aliang的博客 2万+

Ubuntu20.04实时内核补丁PREEMPT_RT编译与安装全流程解析

本文详细解析了在Ubuntu20.04系统上编译与安装实时内核补丁PREEMPT_RT的全流程。从内核与补丁版本匹配、编译环境准备,到内核配置、编译排错,再到最终安装、验证与进阶优化,提供了手把手的实战指南,旨在帮助机器人、工业控制等对实时性有苛刻要求的开发者构建低延迟、高确定性的Linux系统。

weixin_29213827的博客 186

人工智能入门系列之一: 鸢尾花(Iris)多分类的神经网络详解及代码实现

这是最好的时代,我们一起来打造属于自动驾驶汽车上路、无人机飞天、智能机器人管工厂的AI未来 人工智能领域分化为两个阵营:其一是规则式(rule-based)方法,在人工智能早期占主峰;其二是神经网络(neural network)方法,后起之秀。随着硬件水平的提高,算力的指数式增长;人工智能的重心已经从规则式的专家时代转移到神经网络的数据时代。 “神经网络”不选择把人脑熟稔的逻辑规则传授给计算机...

NLP家的码奴小荷的博客 2万+

java实战——图书管理项目

请结合前端一起看一下这个代码,前端中我们需要判断是否success,因此我们的返回值必须有个字段时success可是这样一看的话我们就需要Result,这里我们注意Result是一个模板类,因此我们可以进行套娃,首先先讨一个PageResult这样就可以使得我们的返回值可以显示这个图书的状态,Result可以显示我们后端是否执行成功,只用BookInfo就可以展示每本图书的信息了。然后我们再来看一下它的返回值,我们可以看到它的返回值依然是一个SUCCESS+一个空字符串那就好写了我们直接上代码。

m0_72433000的博客 8432

手把手教你用Cursor + 自定义MCP工具链,让AI帮你搞定App逆向(附adb-mcp/frida-mcp源码)

本文详细介绍了如何利用Cursor IDE与自定义MCP工具链构建AI驱动的App逆向工作流,涵盖adb-mcp和frida-mcp的源码实现与实战应用。通过自然语言指令,AI可自动化完成设备控制、动态Hook和数据分析,显著提升移动安全测试效率。适合安全研究人员和开发者快速掌握智能逆向技术。

weixin_33737134的博客 1301

Java 集合实战练习,零基础入门到精通,收藏这篇就够了

设计一个学生管理系统,使用ArrayList存储学生信息(包括学号String、姓名String、年龄int和成绩double。

Python_0011的博客 1097

【Java】JAVA知识总结浅析

Java是一门功能强大的编程语言,广泛应用于多个领域。Java的编程思想,包括面向过程和面向对象编程,Java的发展历史,各版本的特点,JVM原理,数据类型,Java SE与Java EE的区别,应用场景,JDK与JDBC,Java Web技术,Spring Boot系列,以及MyBatis框架的基本实现,最后还将讨论Java在大数据、人工智能、嵌入式和Android等领域的应用。

wnm23的专栏 5231

SpringBoot4+Java21前后端分离架构项目脚手架

本文介绍了基于SpringBoot 4和Java 21的前后端分离项目架构方案。主要内容包括:1)采用Spring Security 7实现JWT无状态认证和RBAC权限控制;2)后端使用MyBatis-Plus简化数据库操作,前端采用Vue3+Pinia组合;3)详细的项目结构设计,推荐按业务模块分包;4)核心依赖配置和架构设计图,涵盖认证授权流程。该方案结合最新技术栈,提供了生产级的全链路实现,特别适合需要快速构建现代化Web应用的项目。

Hello, New World! 422

Java课程设计详解:图书管理系统,零基础入门到精通,收藏这篇就够了

Java是一种广泛使用的高级编程语言,由Sun Microsystems公司于1995年发布。Java的设计理念是“一次编写,到处运行”,它的核心就是跨平台的特性,使得Java编写的程序能在任何安装了Java虚拟机(JVM)的设备上运行。这为开发者提供了一种便捷的方式来构建一次程序,并部署在不同操作系统上,无需修改源代码。用户需求是系统的外部用户对系统的期望和要求。管理员:负责管理图书馆的书籍、用户和借阅记录。图书管理员:负责维护书籍库存、归还和借出书籍。读者:能够搜索、借阅和归还书籍。

Libra1313的博客 1009

5.1 直流无刷电机(BLDC):基本控制概念

本文系统介绍了直流无刷电机(BLDC)控制系统的核心概念与技术。主要内容包括:控制系统的分层结构设计,开环与闭环控制的原理及特点,PWM调速技术及其调制方式,PID控制算法及其数字化实现方法,以及控制系统的性能评估指标。同时探讨了现代BLDC控制器硬件实现方案,并介绍了磁场定向控制(FOC)、直接转矩控制(DTC)等先进控制策略。文章全面阐述了BLDC电机控制从基本原理到前沿技术的知识体系,为相关应用提供了理论指导和技术参考。

技术工作者 490

Java实现图书管理系统_java图书管理系统,零基础入门到精通,收藏这篇就够了

当我们学完JavaSE,我们就可以自行的完成一个小项目(图书管理系统)这样的一个实战操作,加强我们对基础语法,类核对象,继承和多态,抽象类接口各个知识点的巩固。提示:以下是本篇文章正文内容,下面案例可供参考希望这篇文章能够为您带来一些有价值的信息和启示。在未来的日子里,我们将继续探索更多关于博客技术的精彩内容,敬请期待。如果您有任何问题或建议,欢迎在评论区留言,我们一起交流学习。

leah126的博客 684

uniapp - 详细解决 H5 网页报错 Uncaught Error: Async component timed out after ? ms.(移动端h5页面白屏或加载缓慢失败,超时报错处理)

uni-app,vue3,网页,h5,移动端,手机H5页面,浏览器,报错,uniapp报错,Asynccomponenttimedoutafter,如何解决这个问题,vue3Asynccomponenttimedoutafter,异步组件超时了怎么办,async,详细解决方案,AsyncComponents异步组件,导致页面打不开了,白屏什么也不显示,网页载入非常慢卡顿,vue3网站报错,超时,nuxt3,详细解决方案,浏览器控制台报错,爆红并且页面卡住了,依旧报错,找不到异步组件的报错

🏆 前端领域优质创作者 3776

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Java项目——图书管理系统

功能:系统分管理员界面与用户界面 管理员:实现对图书的增、删、改、查,对所有借阅历史的搜索及所有账户的信息,用户的权限与管理,设定密码,借阅图书及对自己账户的资料修改 用户:实现对图书的借阅功能、查看自己的借阅历史,在用户账户方面实现修改密码以及修改个人信息功能 另外:当数据库中用户表为空,则第一个注册的用户默认为管理员

K.X的博客 8万+

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Java图书管理系统

目录 引言 开发环境 所用技术 项目目录 数据库设计 功能介绍 源码下载 引言 这个项目是当时学完EasyUI前端框架写的一个项目,页面使用的是EasyUI和LayUI。登录用的是SpringSecurity安全控件,对密码进行了加密,登录时可以记住账号,账号会默认保存七天。页面没有在使用JSP了,而是使用的Thymeleaf模板,感觉这个比JSP好用一点(个人看法)。 开发环...

小马同学 3万+

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

基于Java实现的图书管理系统_基于java的图书管理系统,零基础入门到精通,收藏这篇就够了

以上功能的实现不是最主要的,代码的框架是最主要的。怎么实现一个图书管理系统,它的整个脉络是怎样的,这是重要的。上述功能代码的实现可能有不严谨的地方,大家可以自行修改。

leah126的博客 1183

Java 综合项目开发实战:从 0 到 1 打造你的专属项目,收藏这篇就够了

用户认证与权限管理商品管理与分类浏览购物车与订单处理支付接口集成后台管理系统。

Libra1313的博客 1055

【Java 基础篇】Java 图书管理系统详解

图书管理系统是一种用于管理图书信息、借阅记录、用户信息等的软件系统。它可以帮助图书馆、书店或个人管理和组织图书资源,提供了方便的借阅和查询功能。在这篇博客中,我们将详细介绍如何使用Java编程语言创建一个简单的图书管理系统。通过本博客,我们详细介绍了如何使用Java编程语言创建一个简单的图书管理系统。系统包括用户管理模块、图书管理模块和借阅管理模块,以及相应的数据模型、数据访问对象和服务类。此外,我们还提供了一个简单的命令行用户界面,允许用户与系统进行交互。

繁依Fanyi的博客 1万+

java实战——图书管理项目,从零到一,收藏这篇足够了

请结合前端一起看一下这个代码,前端中我们需要判断是否success,因此我们的返回值必须有个字段时success可是这样一看的话我们就需要Result,这里我们注意Result是一个模板类,因此我们可以进行套娃,首先先讨一个PageResult这样就可以使得我们的返回值可以显示这个图书的状态,Result可以显示我们后端是否执行成功,只用BookInfo就可以展示每本图书的信息了。然后我们再来看一下它的返回值,我们可以看到它的返回值依然是一个SUCCESS+一个空字符串那就好写了我们直接上代码。

leah126的博客 872

Java小项目-------图书管理系统_java 图书馆管理系统,零基础入门到精通,收藏这篇就够了

经过上面的操作,我们成功运用我们所学的知识实现了一个小项目,在设计这个系统时,可以使用Java语言进行开发。可以使用面向对象的思想,将图书、借阅记录和用户等实体抽象成类,并使用类之间的关联关系来实现各个功能。同时,在实现过程中我们也巩固了之前所学的内容。其对应的逻辑结构如下:java实现简单的图书管理系统_java怎么创建一个图书馆系统-优快云博客。

Libra1313的博客 674
上一篇: Java常见面试题及答案汇总(2026持续更新)_java面试题,零基础入门到精通,收藏这篇就够了
下一篇: 对象失业半年多了,Java程序员,IT行业是不是再也找不到工作了
程序员_大白
博客等级 码龄5年 1万+粉丝 4001原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值