文章目录
- 项目所需要的技术栈
- 项目演示
- 项目准备工作
- 环境准备
- 数据库数据准备
- 前后端交互分析(前端代码我们使用现成)
- 图书列表界面的创建
- 查看前端发送的请求
- 根据前端接收的返回值来编写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). 用户名称
(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最新版CSDN大礼包:《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最新版CSDN大礼包:《AGI大模型学习资源包》免费分享