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

百度推广是否做网站昆明网站建设哪家便宜

百度推广是否做网站,昆明网站建设哪家便宜,凡科门店通包括哪些产品,免费行情软件在线网站环境搭建#xff1a; 开发规范 接口风格-Restful#xff1a; 统一响应结果-Result#xff1a; 开发流程#xff1a; 第一步应该根据需求定义表结构和定义接口文档 注意#xff1a; 本文代码从上往下一直添加功能#xff0c;后面的模块下的代码包括前面的模块#xff0c…环境搭建 开发规范 接口风格-Restful 统一响应结果-Result 开发流程 第一步应该根据需求定义表结构和定义接口文档 注意 本文代码从上往下一直添加功能后面的模块下的代码包括前面的模块并不是某个模块中的代码只有当前功能。 部门管理 查询部门 思路 代码 Dept实体类 Data NoArgsConstructor AllArgsConstructor public class Dept {private int id;private String name;private LocalDateTime createTime;private LocalDateTime updateTime; } Controller层 Slf4j RestController public class DeptController {Autowiredprivate DeptService deptService;GetMapping(/depts)public Result list() {log.info(查询全部部门信息);ListDept deptList deptService.list();return Result.success(deptList);}}注解Slf4j后可以直接使用log.info输出日志信息 Service层 接口 public interface DeptService {ListDept list();} 实现类 Service public class DeptServiceImpl implements DeptService {Autowiredprivate DeptMapper deptMapper;Overridepublic ListDept list() {return deptMapper.list();} } Mapper层 Mapper public interface DeptMapper {Select(select * from dept)ListDept list();} Postman测试结果 删除部门 思路 代码 Controller层 Slf4j RestController public class DeptController {Autowiredprivate DeptService deptService;/*** 查询部门数据* return*/GetMapping(/depts)public Result list() {log.info(查询全部部门信息);ListDept deptList deptService.list();return Result.success(deptList);}/*** 删除部门* return*/DeleteMapping(/depts/{id})public Result delete(PathVariable Integer id) {log.info(删除id为 id 的部门);deptService.delete(id);return Result.success();}} Service层 接口 public interface DeptService {/*** 查询部门信息* return*/ListDept list();/*** 根据id删除部门* param id*/void delete(Integer id);} 实现类 Service public class DeptServiceImpl implements DeptService {Autowiredprivate DeptMapper deptMapper;/*** 查询部门信息* return*/Overridepublic ListDept list() {return deptMapper.list();}/*** 根据id删除部门* param id*/Overridepublic void delete(Integer id) {deptMapper.deleteById(id);} } Mapper层 Mapper public interface DeptMapper {/*** 查询部门信息* return*/Select(select * from dept)ListDept list();/*** 根据id删除部门* param id*/Delete(delete from dept where id #{id})void deleteById(Integer id); } Postman测试结果 新增部门 思路 代码 Controller层 Slf4j RestController public class DeptController {Autowiredprivate DeptService deptService;/*** 查询部门数据* return*/GetMapping(/depts)public Result list() {log.info(查询全部部门信息);ListDept deptList deptService.list();return Result.success(deptList);}/*** 删除部门* return*/DeleteMapping(/depts/{id})public Result delete(PathVariable Integer id) {log.info(删除id为 id 的部门);deptService.delete(id);return Result.success();}/*** 新增部门* param dept* return*/PostMapping(/depts)public Result insert(RequestBody Dept dept) {log.info(添加部门 dept);deptService.add(dept);return Result.success();}}Service层 接口 public interface DeptService {/*** 查询部门信息* return*/ListDept list();/*** 根据id删除部门* param id*/void delete(Integer id);/*** 新增部门* param dept*/void add(Dept dept); } 实现类 Service public class DeptServiceImpl implements DeptService {Autowiredprivate DeptMapper deptMapper;/*** 查询部门信息* return*/Overridepublic ListDept list() {return deptMapper.list();}/*** 根据id删除部门* param id*/Overridepublic void delete(Integer id) {deptMapper.deleteById(id);}/*** 新增部门* param dept*/Overridepublic void add(Dept dept) {dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());deptMapper.insert(dept);} } Mapper层 Mapper public interface DeptMapper {/*** 查询部门信息* return*/Select(select * from dept)ListDept list();/*** 根据id删除部门* param id*/Delete(delete from dept where id #{id})void deleteById(Integer id);/*** 新增部门* param dept*/Insert(insert into dept(name,create_time,update_time) values (#{name},#{createTime}, #{updateTime}))void insert(Dept dept); } Postman测试结果 优化代码 Controller层优化 路径中/depts每次都出现可以将它提取出来 优化后代码 Slf4j RequestMapping(/depts) RestController public class DeptController {Autowiredprivate DeptService deptService;/*** 查询部门数据* return*/GetMappingpublic Result list() {log.info(查询全部部门信息);ListDept deptList deptService.list();return Result.success(deptList);}/*** 删除部门* return*/DeleteMapping(/{id})public Result delete(PathVariable Integer id) {log.info(删除id为 id 的部门);deptService.delete(id);return Result.success();}/*** 新增部门* param dept* return*/PostMappingpublic Result insert(RequestBody Dept dept) {log.info(添加部门 dept);deptService.add(dept);return Result.success();}} 根据id查找部门 代码 Controller层 Slf4j RequestMapping(/depts) RestController public class DeptController {Autowiredprivate DeptService deptService;/*** 查询部门数据* return*/GetMappingpublic Result list() {log.info(查询全部部门信息);ListDept deptList deptService.list();return Result.success(deptList);}/*** 删除部门* return*/DeleteMapping(/{id})public Result delete(PathVariable Integer id) {log.info(删除id为 id 的部门);deptService.delete(id);return Result.success();}/*** 新增部门* param dept* return*/PostMappingpublic Result insert(RequestBody Dept dept) {log.info(添加部门 dept);deptService.add(dept);return Result.success();}/*** 根据id查找部门* param id* return*/GetMapping(/{id})public Result getById(PathVariable Integer id) {log.info(查询id为 id 的部门信息);Dept dept deptService.get(id);return Result.success(dept);}} Service层 接口 public interface DeptService {/*** 查询部门信息* return*/ListDept list();/*** 根据id删除部门* param id*/void delete(Integer id);/*** 新增部门* param dept*/void add(Dept dept);/*** 根据id查找部门* param id*/Dept get(Integer id); } 实现类 Service public class DeptServiceImpl implements DeptService {Autowiredprivate DeptMapper deptMapper;/*** 查询部门信息* return*/Overridepublic ListDept list() {return deptMapper.list();}/*** 根据id删除部门* param id*/Overridepublic void delete(Integer id) {deptMapper.deleteById(id);}/*** 新增部门* param dept*/Overridepublic void add(Dept dept) {dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());deptMapper.insert(dept);}/*** 根据id查找部门* param id*/Overridepublic Dept get(Integer id) {return deptMapper.getById(id);} } Mapper层 Mapper public interface DeptMapper {/*** 查询部门信息* return*/Select(select * from dept)ListDept list();/*** 根据id删除部门* param id*/Delete(delete from dept where id #{id})void deleteById(Integer id);/*** 新增部门* param dept*/Insert(insert into dept(name,create_time,update_time) values (#{name},#{createTime}, #{updateTime}))void insert(Dept dept);/*** 根据id查找部门* param id* return*/Select(select * from dept where id #{id})Dept getById(Integer id); } Postman测试结果 修改部门 代码 Controller层 Slf4j RequestMapping(/depts) RestController public class DeptController {Autowiredprivate DeptService deptService;/*** 查询部门数据* return*/GetMappingpublic Result list() {log.info(查询全部部门信息);ListDept deptList deptService.list();return Result.success(deptList);}/*** 删除部门* return*/DeleteMapping(/{id})public Result delete(PathVariable Integer id) {log.info(删除id为 id 的部门);deptService.delete(id);return Result.success();}/*** 新增部门* param dept* return*/PostMappingpublic Result insert(RequestBody Dept dept) {log.info(添加部门 dept);deptService.add(dept);return Result.success();}/*** 根据id查找部门* param id* return*/GetMapping(/{id})public Result getById(PathVariable Integer id) {log.info(查询id为 id 的部门信息);Dept dept deptService.get(id);return Result.success(dept);}/*** 修改部门* param dept* return*/PutMappingpublic Result update(RequestBody Dept dept) {log.info(修改部门 dept);deptService.update(dept);return Result.success();}} Service层 接口 public interface DeptService {/*** 查询部门信息* return*/ListDept list();/*** 根据id删除部门* param id*/void delete(Integer id);/*** 新增部门* param dept*/void add(Dept dept);/*** 根据id查找部门* param id*/Dept get(Integer id);/*** 修改部门* param dept*/void update(Dept dept); }实现类 Service public class DeptServiceImpl implements DeptService {Autowiredprivate DeptMapper deptMapper;/*** 查询部门信息* return*/Overridepublic ListDept list() {return deptMapper.list();}/*** 根据id删除部门* param id*/Overridepublic void delete(Integer id) {deptMapper.deleteById(id);}/*** 新增部门* param dept*/Overridepublic void add(Dept dept) {dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());deptMapper.insert(dept);}/*** 根据id查找部门* param id*/Overridepublic Dept get(Integer id) {return deptMapper.getById(id);}/*** 修改部门* param dept*/Overridepublic void update(Dept dept) {dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());deptMapper.update(dept);} } Mapper层 Mapper public interface DeptMapper {/*** 查询部门信息* return*/Select(select * from dept)ListDept list();/*** 根据id删除部门* param id*/Delete(delete from dept where id #{id})void deleteById(Integer id);/*** 新增部门* param dept*/Insert(insert into dept(name,create_time,update_time) values (#{name},#{createTime}, #{updateTime}))void insert(Dept dept);/*** 根据id查找部门* param id* return*/Select(select * from dept where id #{id})Dept getById(Integer id);/*** 修改部门* param dept*/Update(update dept set name #{name},create_time #{createTime},update_time #{updateTime} where id #{id})void update(Dept dept); } Postman测试结果 员工管理 分页查询 思路 代码 Emp实体类 Data NoArgsConstructor AllArgsConstructor public class Emp {private Integer id;private String username;private String password;private String name;private Short gender;private String image;private Short job;private LocalDate entryDate;private Integer deptId;private LocalDateTime createTime;private LocalDateTime updateTime; }Controller层 Slf4j RequestMapping(/emps) RestController public class EmpController {Autowiredprivate EmpService empService;/*** 根据每页记录数和页码获取页面实体类* return*/GetMappingpublic Result getPage(RequestParam(defaultValue 1) Integer page,RequestParam(defaultValue 10) Integer pageSize) {log.info(每页记录数{}查询页码{},pageSize,page);PageBean pb empService.getPage(page,pageSize);return Result.success(pb);}} Service层 接口 public interface EmpService {/*** 根据每页记录数和页码获取页面实体类* return*/PageBean getPage(Integer page, Integer pageSize);} 实现类 Service public class EmpServiceImpl implements EmpService {Autowiredprivate EmpMapper empMapper;/*** 分页查询获取列表数据* param page* param pageSize* return*/Overridepublic PageBean getPage(Integer page, Integer pageSize) {Long total empMapper.getTotal();Long start (long) ((page - 1) * pageSize);ListEmp rows empMapper.getRows(start,pageSize);PageBean pageBean new PageBean(total,rows);return pageBean;} } Mapper层 Mapper public interface EmpMapper {/*** 获取总记录数* return*/Select(select count(*) from emp;)Long getTotal();/*** 分页查询获取列表数据* param start* param pageSize* return*/Select(select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time\n from emp limit #{start},#{pageSize})ListEmp getRows(Long start, Integer pageSize);} Postman测试结果 分页插件-PageHelper 由下图可以看到原始方式分页查询步骤固定而且代码繁琐我们可以使用PageHelper插件简化代码。 代码演示 导入依赖 !--PageHelper分页插件--dependencygroupIdcom.github.pagehelper/groupIdartifactIdpagehelper-spring-boot-starter/artifactIdversion1.4.6/version/dependency 修改代码 Mapper层 Mapper public interface EmpMapper { // /** // * 获取总记录数 // * return // */ // Select(select count(*) from emp) // Long getTotal(); // // /** // * 分页查询获取列表数据 // * param start // * param pageSize // * return // */ // Select(select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time\n // from emp limit #{start},#{pageSize}) // ListEmp getRows(Long start, Integer pageSize);/*** 使用PageHelper插件来进行分页查询*/Select(select * from emp)ListEmp list();} Service层 实现类 Service public class EmpServiceImpl implements EmpService {Autowiredprivate EmpMapper empMapper;// /** // * 分页查询获取列表数据 // * param page // * param pageSize // * return // */ // Override // public PageBean getPage(Integer page, Integer pageSize) { // Long total empMapper.getTotal(); // Long start (long) ((page - 1) * pageSize); // ListEmp rows empMapper.getRows(start,pageSize); // PageBean pageBean new PageBean(total,rows); // return pageBean; // }/*** 使用PageHelper分页插件进行分页查询*/Overridepublic PageBean getPage(Integer page, Integer pageSize) {//1.设置分页参数PageHelper.startPage(page, pageSize);//2.执行查询ListEmp empList empMapper.list();PageEmp p (PageEmp) empList;//3.封装PageBean对象PageBean pageBean new PageBean(p.getTotal(),p.getResult());return pageBean;}} 分页条件查询 措施 代码 Controller层 Slf4j RequestMapping(/emps) RestController public class EmpController {Autowiredprivate EmpService empService;/*** 根据每页记录数和页码获取页面实体类* return*/GetMappingpublic Result getPage(RequestParam(defaultValue 1) Integer page,RequestParam(defaultValue 10) Integer pageSize,String name, Short gender,DateTimeFormat(pattern yyyy-MM-dd) LocalDate begin,DateTimeFormat(pattern yyyy-MM-dd) LocalDate end) {log.info(每页记录数{}查询页码{},pageSize,page);PageBean pb empService.getPage(page,pageSize,name,gender,begin,end);return Result.success(pb);}} Service层 接口 public interface EmpService {/*** 根据每页记录数和页码获取页面实体类* return*/PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end);} 实现类 Service public class EmpServiceImpl implements EmpService {Autowiredprivate EmpMapper empMapper;// /** // * 分页查询获取列表数据 // * param page // * param pageSize // * return // */ // Override // public PageBean getPage(Integer page, Integer pageSize) { // Long total empMapper.getTotal(); // Long start (long) ((page - 1) * pageSize); // ListEmp rows empMapper.getRows(start,pageSize); // PageBean pageBean new PageBean(total,rows); // return pageBean; // }/*** 使用PageHelper分页插件进行分页查询*/Overridepublic PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {//1.设置分页参数PageHelper.startPage(page, pageSize);//2.执行查询ListEmp empList empMapper.list(name,gender,begin,end);PageEmp p (PageEmp) empList;//3.封装PageBean对象PageBean pageBean new PageBean(p.getTotal(),p.getResult());return pageBean;}} Mapper层 Mapper public interface EmpMapper { // /** // * 获取总记录数 // * return // */ // Select(select count(*) from emp) // Long getTotal(); // // /** // * 分页查询获取列表数据 // * param start // * param pageSize // * return // */ // Select(select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time\n // from emp limit #{start},#{pageSize}) // ListEmp getRows(Long start, Integer pageSize);/*** 使用PageHelper插件来进行分页查询*///动态SQLListEmp list(String name, Short gender, LocalDate begin, LocalDate end);} 动态SQL: xml文件: ?xml version1.0 encodingUTF-8 ? !DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.han.mapper.EmpMapperselect idlist resultTypecom.han.pojo.Empselect id,username,password,name,gender,image,job,entrydate,dept_id,create_time,update_timefrom empwhereif testname ! null and name ! name like concat(%,#{name},%)/ifif testgender ! nulland gender #{gender}/ifif testbegin ! null and end ! nulland entrydate between #{begin} and #{end}/if/whereorder by update_time DESC/select /mapper Postman测试结果 删除员工 代码 Controller层 Slf4j RequestMapping(/emps) RestController public class EmpController {Autowiredprivate EmpService empService;/*** 根据每页记录数和页码获取页面实体类* return*/GetMappingpublic Result getPage(RequestParam(defaultValue 1) Integer page,RequestParam(defaultValue 10) Integer pageSize,String name, Short gender,DateTimeFormat(pattern yyyy-MM-dd) LocalDate begin,DateTimeFormat(pattern yyyy-MM-dd) LocalDate end) {log.info(每页记录数{}查询页码{},pageSize,page);PageBean pb empService.getPage(page,pageSize,name,gender,begin,end);return Result.success(pb);}/*** 批量删除员工* param ids* return*/DeleteMapping(/{ids})public Result delete(PathVariable(ids) ListShort ids) {log.info(批量删除操作ids:{},ids);empService.delete(ids);return Result.success();}} Service层 接口 public interface EmpService {/*** 根据每页记录数和页码获取页面实体类* return*/PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end);/*** 批量删除员工* param ids*/void delete(ListShort ids); } 实现类 Service public class EmpServiceImpl implements EmpService {Autowiredprivate EmpMapper empMapper;// /** // * 分页查询获取列表数据 // * param page // * param pageSize // * return // */ // Override // public PageBean getPage(Integer page, Integer pageSize) { // Long total empMapper.getTotal(); // Long start (long) ((page - 1) * pageSize); // ListEmp rows empMapper.getRows(start,pageSize); // PageBean pageBean new PageBean(total,rows); // return pageBean; // }/*** 使用PageHelper分页插件进行分页查询*/Overridepublic PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {//1.设置分页参数PageHelper.startPage(page, pageSize);//2.执行查询ListEmp empList empMapper.list(name,gender,begin,end);PageEmp p (PageEmp) empList;//3.封装PageBean对象PageBean pageBean new PageBean(p.getTotal(),p.getResult());return pageBean;}/*** 批量删除员工* param ids*/Overridepublic void delete(ListShort ids) {empMapper.delete(ids);}} Mapper层 Mapper public interface EmpMapper { // /** // * 获取总记录数 // * return // */ // Select(select count(*) from emp) // Long getTotal(); // // /** // * 分页查询获取列表数据 // * param start // * param pageSize // * return // */ // Select(select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time\n // from emp limit #{start},#{pageSize}) // ListEmp getRows(Long start, Integer pageSize);//动态SQL/*** 使用PageHelper插件来进行分页查询*/ListEmp list(String name, Short gender, LocalDate begin, LocalDate end);/*** 批量删除员工* param ids*/void delete(ListShort ids);} 动态SQL: xml文件: ?xml version1.0 encodingUTF-8 ? !DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.han.mapper.EmpMapperselect idlist resultTypecom.han.pojo.Empselect id,username,password,name,gender,image,job,entrydate,dept_id,create_time,update_timefrom empwhereif testname ! null and name ! name like concat(%,#{name},%)/ifif testgender ! nulland gender #{gender}/ifif testbegin ! null and end ! nulland entrydate between #{begin} and #{end}/if/whereorder by update_time DESC/selectdelete iddeletedeletefrom empwhere id inforeach collectionids itemid separator, open( close)#{id}/foreach/delete/mapper Postman测试结果 文件上传 本地存储不推荐 使用MultipartFile类型接收文件再使用下面的方法 阿里云OSS存储推荐 用户上文中图像的上传 代码演示 工具类 /*** 阿里云 OSS 工具类*/ RestController public class AliOSSUtils {/*** 实现上传图片到OSS*/public String upload(MultipartFile file) throws ClientException, IOException {InputStream inputStream file.getInputStream();// 以华东1杭州的外网Endpoint为例其它Region请按实际情况填写。String endpoint https://oss-cn-beijing.aliyuncs.com;// 从环境变量中获取访问凭证。运行本代码示例之前请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。EnvironmentVariableCredentialsProvider credentialsProvider CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Bucket名称例如examplebucket。String bucketName web-talias-test;// 填写Object完整路径例如exampleobject.txt。Object完整路径中不能包含Bucket名称。String objectName file.getOriginalFilename();String fileName UUID.randomUUID().toString() objectName.substring(objectName.lastIndexOf(.));// 填写本地文件的完整路径例如D:\\localpath\\examplefile.txt。// 如果未指定本地路径则默认从示例程序所属项目对应本地路径中上传文件。// 创建OSSClient实例OSS ossClient new OSSClientBuilder().build(endpoint, credentialsProvider);// 创建PutObjectRequest对象。PutObjectRequest putObjectRequest new PutObjectRequest(bucketName, fileName, inputStream);// 上传文件。PutObjectResult result ossClient.putObject(putObjectRequest);// 设置请求头。MapString, String headers new HashMapString, String();/*// 指定Object的存储类型。headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());// 指定ContentType。headers.put(OSSHeaders.CONTENT_TYPE, text/txt);*/// 设置用户自定义元数据。MapString, String userMetadata new HashMapString, String();/*userMetadata.put(key1,value1);userMetadata.put(key2,value2);*/URL signedUrl null;// 指定生成的签名URL过期时间单位为毫秒。本示例以设置过期时间为1小时为例。Date expiration new Date(new Date().getTime() 3600 * 1000L);// 生成签名URL。GeneratePresignedUrlRequest request new GeneratePresignedUrlRequest(bucketName, fileName);// 设置过期时间。request.setExpiration(expiration);// 将请求头加入到request中。request.setHeaders(headers);// 添加用户自定义元数据。request.setUserMetadata(userMetadata);// 通过HTTP PUT请求生成签名URL。signedUrl ossClient.generatePresignedUrl(request);// 返回签名URL。ossClient.shutdown();return signedUrl.toString().split(\\?)[0];}} 文件上传Controller层 Slf4j RestController public class UploadController {Autowiredprivate AliOSSUtils aliOSSUtils;PostMapping(/upload)public Result upload(MultipartFile image) throws IOException, ClientException {log.info(接收到文件:{},image.getOriginalFilename());String url aliOSSUtils.upload(image);log.info(已将文件存储到阿里云OSS,url:{},url);return Result.success(url);}} 修改员工 1.查询回显 代码 Controller层 Slf4j RequestMapping(/emps) RestController public class EmpController {Autowiredprivate EmpService empService;/*** 根据每页记录数和页码获取页面实体类* return*/GetMappingpublic Result getPage(RequestParam(defaultValue 1) Integer page,RequestParam(defaultValue 10) Integer pageSize,String name, Short gender,DateTimeFormat(pattern yyyy-MM-dd) LocalDate begin,DateTimeFormat(pattern yyyy-MM-dd) LocalDate end) {log.info(每页记录数{}查询页码{},pageSize,page);PageBean pb empService.getPage(page,pageSize,name,gender,begin,end);return Result.success(pb);}/*** 批量删除员工* param ids* return*/DeleteMapping(/{ids})public Result delete(PathVariable(ids) ListShort ids) {log.info(批量删除操作ids:{},ids);empService.delete(ids);return Result.success();}/*** 新增员工* param emp* return*/PostMappingpublic Result add(RequestBody Emp emp) {log.info(新增员工{},emp);empService.add(emp);return Result.success();}/*** 根据id查询员工* param id* return*/GetMapping(/{id})public Result getById(PathVariable Integer id) {log.info(查询id为:{}的员工,id);Emp emp empService.getById(id);return Result.success(emp);}} Service层 接口 public interface EmpService {/*** 根据每页记录数和页码获取页面实体类* return*/PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end);/*** 批量删除员工* param ids*/void delete(ListShort ids);/*** 新增员工* param emp*/void add(Emp emp);/*** 根据id查询员工* return*/Emp getById(Integer id); } 实现类 Service public class EmpServiceImpl implements EmpService {Autowiredprivate EmpMapper empMapper;// /** // * 分页查询获取列表数据 // * param page // * param pageSize // * return // */ // Override // public PageBean getPage(Integer page, Integer pageSize) { // Long total empMapper.getTotal(); // Long start (long) ((page - 1) * pageSize); // ListEmp rows empMapper.getRows(start,pageSize); // PageBean pageBean new PageBean(total,rows); // return pageBean; // }/*** 使用PageHelper分页插件进行分页查询*/Overridepublic PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {//1.设置分页参数PageHelper.startPage(page, pageSize);//2.执行查询ListEmp empList empMapper.list(name,gender,begin,end);PageEmp p (PageEmp) empList;//3.封装PageBean对象PageBean pageBean new PageBean(p.getTotal(),p.getResult());return pageBean;}/*** 批量删除员工* param ids*/Overridepublic void delete(ListShort ids) {empMapper.delete(ids);}/*** 新增员工* param emp*/Overridepublic void add(Emp emp) {emp.setUpdateTime(LocalDateTime.now());emp.setCreateTime(LocalDateTime.now());empMapper.add(emp);}/*** 根据id查询员工* return*/Overridepublic Emp getById(Integer id) {Emp emp empMapper.get(id);return emp;}}Mapper层 Mapper public interface EmpMapper { // /** // * 获取总记录数 // * return // */ // Select(select count(*) from emp) // Long getTotal(); // // /** // * 分页查询获取列表数据 // * param start // * param pageSize // * return // */ // Select(select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time\n // from emp limit #{start},#{pageSize}) // ListEmp getRows(Long start, Integer pageSize);//动态SQL/*** 使用PageHelper插件来进行分页查询*/ListEmp list(String name, Short gender, LocalDate begin, LocalDate end);/*** 批量删除员工* param ids*/void delete(ListShort ids);/*** 新增员工* param emp*/Insert(insert into emp (username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values (#{username},#{name},#{gender},#{image},#{job},#{entryDate},#{deptId},#{createTime},#{updateTime}))void add(Emp emp);Select(select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp where id #{id})Emp get(Integer id); }Postman测试结果 2.修改员工 代码 Controller层 Slf4j RequestMapping(/emps) RestController public class EmpController {Autowiredprivate EmpService empService;/*** 根据每页记录数和页码获取页面实体类* return*/GetMappingpublic Result getPage(RequestParam(defaultValue 1) Integer page,RequestParam(defaultValue 10) Integer pageSize,String name, Short gender,DateTimeFormat(pattern yyyy-MM-dd) LocalDate begin,DateTimeFormat(pattern yyyy-MM-dd) LocalDate end) {log.info(每页记录数{}查询页码{},pageSize,page);PageBean pb empService.getPage(page,pageSize,name,gender,begin,end);return Result.success(pb);}/*** 批量删除员工* param ids* return*/DeleteMapping(/{ids})public Result delete(PathVariable(ids) ListShort ids) {log.info(批量删除操作ids:{},ids);empService.delete(ids);return Result.success();}/*** 新增员工* param emp* return*/PostMappingpublic Result add(RequestBody Emp emp) {log.info(新增员工{},emp);empService.add(emp);return Result.success();}/*** 根据id查询员工* param id* return*/GetMapping(/{id})public Result getById(PathVariable Integer id) {log.info(查询id为:{}的员工,id);Emp emp empService.getById(id);return Result.success(emp);}/*** 修改员工* param emp* return*/PutMappingpublic Result update(RequestBody Emp emp) {log.info(修改员工{},emp);empService.update(emp);return Result.success();}} Service层 接口 public interface EmpService {/*** 根据每页记录数和页码获取页面实体类* return*/PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end);/*** 批量删除员工* param ids*/void delete(ListShort ids);/*** 新增员工* param emp*/void add(Emp emp);/*** 根据id查询员工* return*/Emp getById(Integer id);void update(Emp emp); } 实现类 Service public class EmpServiceImpl implements EmpService {Autowiredprivate EmpMapper empMapper;// /** // * 分页查询获取列表数据 // * param page // * param pageSize // * return // */ // Override // public PageBean getPage(Integer page, Integer pageSize) { // Long total empMapper.getTotal(); // Long start (long) ((page - 1) * pageSize); // ListEmp rows empMapper.getRows(start,pageSize); // PageBean pageBean new PageBean(total,rows); // return pageBean; // }/*** 使用PageHelper分页插件进行分页查询*/Overridepublic PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {//1.设置分页参数PageHelper.startPage(page, pageSize);//2.执行查询ListEmp empList empMapper.list(name,gender,begin,end);PageEmp p (PageEmp) empList;//3.封装PageBean对象PageBean pageBean new PageBean(p.getTotal(),p.getResult());return pageBean;}/*** 批量删除员工* param ids*/Overridepublic void delete(ListShort ids) {empMapper.delete(ids);}/*** 新增员工* param emp*/Overridepublic void add(Emp emp) {emp.setUpdateTime(LocalDateTime.now());emp.setCreateTime(LocalDateTime.now());empMapper.add(emp);}/*** 根据id查询员工* return*/Overridepublic Emp getById(Integer id) {Emp emp empMapper.get(id);return emp;}Overridepublic void update(Emp emp) {emp.setUpdateTime(LocalDateTime.now());empMapper.update(emp);}}Mapper层 Mapper public interface EmpMapper { // /** // * 获取总记录数 // * return // */ // Select(select count(*) from emp) // Long getTotal(); // // /** // * 分页查询获取列表数据 // * param start // * param pageSize // * return // */ // Select(select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time\n // from emp limit #{start},#{pageSize}) // ListEmp getRows(Long start, Integer pageSize);//动态SQL/*** 使用PageHelper插件来进行分页查询*/ListEmp list(String name, Short gender, LocalDate begin, LocalDate end);/*** 批量删除员工* param ids*/void delete(ListShort ids);/*** 新增员工* param emp*/Insert(insert into emp (username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime}))void add(Emp emp);/*** 根据id查询员工* param id* return*/Select(select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp where id #{id})Emp get(Integer id);/*** 修改员工* param emp*/void update(Emp emp); } 动态SQL xml文件 ?xml version1.0 encodingUTF-8 ? !DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.han.mapper.EmpMapperselect idlist resultTypecom.han.pojo.Empselect id,username,password,name,gender,image,job,entrydate,dept_id,create_time,update_timefrom empwhereif testname ! null and name ! name like concat(%,#{name},%)/ifif testgender ! nulland gender #{gender}/ifif testbegin ! null and end ! nulland entrydate between #{begin} and #{end}/if/whereorder by update_time DESC/selectdelete iddeletedeletefrom empwhere id inforeach collectionids itemid separator, open( close)#{id}/foreach/deleteupdate idupdateupdate empsetif testimage ! null and image !image #{image},/ifif testusername ! null and image !username #{username},/ifif testname ! null and image !name #{name},/ifif testgender ! nullgender #{gender},/ifif testjob ! nulljob #{job},/ifif testentrydate ! nullentrydate #{entrydate},/ifif testdeptId ! nulldept_id #{deptId},/ifupdate_time #{updateTime}/setwhere id #{id}/update/mapper Postman测试结果 配置文件 1.参数配置化 因为将文件上传阿里云OSS总是需要endpoint和bucketName但是这些还是固定的所以直接将它们存储在配置文件中 代码演示 配置文件applicat-properties #自定义的阿里云OSS配置信息 aliyun.oss.endpointhttps://oss-cn-beijing.aliyuncs.com aliyun.oss.bucketNameweb-talias-test 工具类 /*** 阿里云 OSS 工具类*/ RestController public class AliOSSUtils {// 以华东1杭州的外网Endpoint为例其它Region请按实际情况填写。Value(${aliyun.oss.endpoint})private String endpoint;// 填写Bucket名称例如examplebucket。Value(${aliyun.oss.bucketName})private String bucketName;/*** 实现上传图片到OSS*/public String upload(MultipartFile file) throws ClientException, IOException {InputStream inputStream file.getInputStream();// 从环境变量中获取访问凭证。运行本代码示例之前请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。EnvironmentVariableCredentialsProvider credentialsProvider CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Object完整路径例如exampleobject.txt。Object完整路径中不能包含Bucket名称。String objectName file.getOriginalFilename();String fileName UUID.randomUUID().toString() objectName.substring(objectName.lastIndexOf(.));// 填写本地文件的完整路径例如D:\\localpath\\examplefile.txt。// 如果未指定本地路径则默认从示例程序所属项目对应本地路径中上传文件。// 创建OSSClient实例OSS ossClient new OSSClientBuilder().build(endpoint, credentialsProvider);// 创建PutObjectRequest对象。PutObjectRequest putObjectRequest new PutObjectRequest(bucketName, fileName, inputStream);// 上传文件。PutObjectResult result ossClient.putObject(putObjectRequest);// 设置请求头。MapString, String headers new HashMapString, String();/*// 指定Object的存储类型。headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());// 指定ContentType。headers.put(OSSHeaders.CONTENT_TYPE, text/txt);*/// 设置用户自定义元数据。MapString, String userMetadata new HashMapString, String();/*userMetadata.put(key1,value1);userMetadata.put(key2,value2);*/URL signedUrl null;// 指定生成的签名URL过期时间单位为毫秒。本示例以设置过期时间为1小时为例。Date expiration new Date(new Date().getTime() 3600 * 1000L);// 生成签名URL。GeneratePresignedUrlRequest request new GeneratePresignedUrlRequest(bucketName, fileName);// 设置过期时间。request.setExpiration(expiration);// 将请求头加入到request中。request.setHeaders(headers);// 添加用户自定义元数据。request.setUserMetadata(userMetadata);// 通过HTTP PUT请求生成签名URL。signedUrl ossClient.generatePresignedUrl(request);// 返回签名URL。ossClient.shutdown();return signedUrl.toString().split(\\?)[0];}} 2.(推荐)ymlyaml配置文件 常见配置文件格式对比 yml基本语法 数据格式 代码演示 将下面application.properties文件改写成application.yml文件 application.properties: spring.application.nametlias #驱动器名称 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver #数据库连接的url spring.datasource.urljdbc:mysql://localhost:3306/tlias #连接数据库的用户名 spring.datasource.usernameroot #连接数据库的密码 spring.datasource.password123456#配置mybatis的日志指定输出到控制台 mybatis.configuration.log-implorg.apache.ibatis.logging.stdout.StdOutImpl #开启mybatis的驼峰命名自动映射开关 mybatis.configuration.map-underscore-to-camel-casetrue#自定义的阿里云OSS配置信息 aliyun.oss.endpointhttps://oss-cn-beijing.aliyuncs.com aliyun.oss.bucketNameweb-talias-test application.yml: spring:application:name: tlias#数据库连接信息datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/tliasusername: rootpassword: 123456#文件上传的配置servlet:multipart:max-file-size: 10MBmax-request-size: 100MB #mybatis配置 mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: true#阿里云OSS配置 aliyun:oss:endpoint: https://oss-cn-beijing.aliyuncs.combucketName: web-talias-test3.ConfigurationProperties 与Value的区别 应用场景 如果需要注解的属性只有一两个而且只需要注解一次那么使用Value注解如果需要注解的属性较多而且需要多次注解就使用ConfigurationProperties注解。 代码演示 AliOSSProperties Data Component ConfigurationProperties(prefix aliyun.oss) public class AliOSSProperties {private String endpoint;private String bucketName; } AliOSSUtils /*** 阿里云 OSS 工具类*/ RestController public class AliOSSUtils {// // 以华东1杭州的外网Endpoint为例其它Region请按实际情况填写。 // Value(${aliyun.oss.endpoint}) // private String endpoint; // // 填写Bucket名称例如examplebucket。 // Value(${aliyun.oss.bucketName}) // private String bucketName;Autowiredprivate AliOSSProperties aliOSSProperties;/*** 实现上传图片到OSS*/public String upload(MultipartFile file) throws ClientException, IOException {String endpoint aliOSSProperties.getEndpoint();String bucketName aliOSSProperties.getBucketName();InputStream inputStream file.getInputStream();// 从环境变量中获取访问凭证。运行本代码示例之前请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。EnvironmentVariableCredentialsProvider credentialsProvider CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Object完整路径例如exampleobject.txt。Object完整路径中不能包含Bucket名称。String objectName file.getOriginalFilename();String fileName UUID.randomUUID().toString() objectName.substring(objectName.lastIndexOf(.));// 填写本地文件的完整路径例如D:\\localpath\\examplefile.txt。// 如果未指定本地路径则默认从示例程序所属项目对应本地路径中上传文件。// 创建OSSClient实例OSS ossClient new OSSClientBuilder().build(endpoint, credentialsProvider);// 创建PutObjectRequest对象。PutObjectRequest putObjectRequest new PutObjectRequest(bucketName, fileName, inputStream);// 上传文件。PutObjectResult result ossClient.putObject(putObjectRequest);// 设置请求头。MapString, String headers new HashMapString, String();/*// 指定Object的存储类型。headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());// 指定ContentType。headers.put(OSSHeaders.CONTENT_TYPE, text/txt);*/// 设置用户自定义元数据。MapString, String userMetadata new HashMapString, String();/*userMetadata.put(key1,value1);userMetadata.put(key2,value2);*/URL signedUrl null;// 指定生成的签名URL过期时间单位为毫秒。本示例以设置过期时间为1小时为例。Date expiration new Date(new Date().getTime() 3600 * 1000L);// 生成签名URL。GeneratePresignedUrlRequest request new GeneratePresignedUrlRequest(bucketName, fileName);// 设置过期时间。request.setExpiration(expiration);// 将请求头加入到request中。request.setHeaders(headers);// 添加用户自定义元数据。request.setUserMetadata(userMetadata);// 通过HTTP PUT请求生成签名URL。signedUrl ossClient.generatePresignedUrl(request);// 返回签名URL。ossClient.shutdown();return signedUrl.toString().split(\\?)[0];}} 登录功能 基础登录功能代码 Controller层 Slf4j RestController public class LoginController {AutowiredEmpService empService;PostMapping(/login)public Result login(RequestBody Emp emp) {log.info(用户尝试登录登录信息{},emp);Boolean result empService.login(emp);/*if(result){return Result.success();} else {return Result.error(用户名或密码错误!);}*/return result true ? Result.success() : Result.error(用户名或密码错误);}} Service层 接口 public interface EmpService {/*** 根据每页记录数和页码获取页面实体类* return*/PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end);/*** 批量删除员工* param ids*/void delete(ListShort ids);/*** 新增员工* param emp*/void add(Emp emp);/*** 根据id查询员工* return*/Emp getById(Integer id);void update(Emp emp);Boolean login(Emp emp); }实现类 Service public class EmpServiceImpl implements EmpService {Autowiredprivate EmpMapper empMapper;// /** // * 分页查询获取列表数据 // * param page // * param pageSize // * return // */ // Override // public PageBean getPage(Integer page, Integer pageSize) { // Long total empMapper.getTotal(); // Long start (long) ((page - 1) * pageSize); // ListEmp rows empMapper.getRows(start,pageSize); // PageBean pageBean new PageBean(total,rows); // return pageBean; // }/*** 使用PageHelper分页插件进行分页查询*/Overridepublic PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {//1.设置分页参数PageHelper.startPage(page, pageSize);//2.执行查询ListEmp empList empMapper.list(name,gender,begin,end);PageEmp p (PageEmp) empList;//3.封装PageBean对象PageBean pageBean new PageBean(p.getTotal(),p.getResult());return pageBean;}/*** 批量删除员工* param ids*/Overridepublic void delete(ListShort ids) {empMapper.delete(ids);}/*** 新增员工* param emp*/Overridepublic void add(Emp emp) {emp.setUpdateTime(LocalDateTime.now());emp.setCreateTime(LocalDateTime.now());empMapper.add(emp);}/*** 根据id查询员工* return*/Overridepublic Emp getById(Integer id) {Emp emp empMapper.get(id);return emp;}Overridepublic void update(Emp emp) {emp.setUpdateTime(LocalDateTime.now());empMapper.update(emp);}Overridepublic Boolean login(Emp emp) {Short count empMapper.getByUsernameAndPassword(emp);if(count 1){return true;} else {return false;}}} Mapper层 Mapper public interface EmpMapper { // /** // * 获取总记录数 // * return // */ // Select(select count(*) from emp) // Long getTotal(); // // /** // * 分页查询获取列表数据 // * param start // * param pageSize // * return // */ // Select(select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time\n // from emp limit #{start},#{pageSize}) // ListEmp getRows(Long start, Integer pageSize);//动态SQL/*** 使用PageHelper插件来进行分页查询*/ListEmp list(String name, Short gender, LocalDate begin, LocalDate end);/*** 批量删除员工* param ids*/void delete(ListShort ids);/*** 新增员工* param emp*/Insert(insert into emp (username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values (#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime}))void add(Emp emp);/*** 根据id查询员工* param id* return*/Select(select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp where id #{id})Emp get(Integer id);/*** 修改员工* param emp*/void update(Emp emp);Select(select count(*) from emp where username #{username} and password #{password})Short getByUsernameAndPassword(Emp emp); } Postman测试结果 问题 使用上面的基础登录功能代码运行程序会有一些问题比如直接访问接口路径浏览器会直接跳到对应的接口网址页面而不需要登录操作。为了解决这一问题我们需要进行登录校验 登录校验 会话技术 会话跟踪方案 1.Cookie 2.Session 3★.令牌技术推荐 JWT令牌 使用场景 最广泛的使用场景登录认证 JWT生成 导入依赖 dependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt/artifactIdversion0.9.1/version/dependency 代码演示 /*** 生成JWT令牌*/Testvoid testJwt() {MapString, Object claims new HashMap();claims.put(username, admin);claims.put(password, 123456);String jwt Jwts.builder().signWith(SignatureAlgorithm.HS256, hann)//签名算法.setClaims(claims)//自定义内容载荷.setExpiration(new Date(System.currentTimeMillis() 3600 * 1000))//设置有效期1h.compact();System.out.println(jwt);}/*** 解析JWT令牌*/Testvoid testParseJwt(){Claims claims Jwts.parser().setSigningKey(hann)//指定签名密钥.parseClaimsJws(eyJhbGciOiJIUzI1NiJ9 .eyJwYXNzd29yZCI6IjEyMzQ1NiIsImV4cCI6MTcxNzQwNTg3NywidXNlcm5hbWUiOiJhZG1pbiJ9 .iup_46wg3STPq6Dffbt36IYKTbN8cwiRcOm_8uI_slY)//解析令牌.getBody();System.out.println(claims);} 注意事项 接下来通过jwt令牌进行登录校验。 改写登录功能 思路 1.生成JWT令牌 代码演示 这里我发现之前基础的登录功能只返回一个布尔类型的值是只能获取到用户名和密码的但是在生成JWT令牌是自定义内容写用户名和密码是可以被解码的这样信息就不安全所以我把登录的一系列接口和方法返回的类型改成Emp实体类了 JWT令牌工具类 public class JwtUtils {private static String signKey hann;private static Long expirationTime 43200000L;/*** 获得JWT令牌*/public static String getJwt(MapString, Object claims) {String jwt Jwts.builder().signWith(SignatureAlgorithm.HS256, signKey)//签名算法.setClaims(claims)//自定义内容载荷.setExpiration(new Date(System.currentTimeMillis() expirationTime))//设置有效期12h.compact();return jwt;}} Controller层 Slf4j RestController public class LoginController {AutowiredEmpService empService;PostMapping(/login)public Result login(RequestBody Emp emp) {log.info(用户尝试登录登录信息{},emp);Emp e empService.login(emp);if(e ! null){//登录成功MapString, Object map new HashMap();map.put(id, e.getId());map.put(name, e.getName());map.put(username, e.getUsername());String jwt JwtUtils.getJwt(map);return Result.success(jwt);} else {return Result.error(用户名或密码错误!);}}} Postman测试结果 2.统一校验JWT令牌 ①过滤器Filter 使用方法 注解WebFilter中urlPatterns /*表示拦截所有路径。 执行流程 拦截路径 过滤器链 登录校验流程 代码 pom.xml 引入依赖用于将Result对象转为JSON格式 dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.76/version/dependency Filter Slf4j WebFilter public class LoginCheckFilter implements Filter {Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest req (HttpServletRequest) servletRequest;HttpServletResponse resp (HttpServletResponse) servletResponse;//1.获取urlString url req.getRequestURL().toString();//2.判断url中是否包含login如果有直接放行如果没有需要再判断if(url.contains(login)) {log.info(登录操作放行);filterChain.doFilter(servletRequest, servletResponse);return;}//3.获取请求头中的令牌String jwt req.getHeader(token);//4.判断令牌是否存在若存在继续判断不存在则返回未登录信息if(!StringUtils.hasLength(jwt)) {log.info(请求头token为空返回未登录信息);Result error Result.error(NOT_LOGIN);//手动转换 对象-JSON 格式 利用阿里巴巴fastJSONString notLogin JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return;}//令牌存在判断令牌是否合法不合法返回未登录信息try {JwtUtils.parseJwt(jwt);} catch (Exception e) {e.printStackTrace();log.info(解析令牌失败返回未登录信息);Result error Result.error(NOT_LOGIN);//手动转换 对象-JSON 格式 利用阿里巴巴fastJSONString notLogin JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return;}//放行log.info(令牌合法放行,jwt:{},jwt);filterChain.doFilter(servletRequest, servletResponse);} } Postman测试 ②拦截器Interceptor 使用方法 拦截路径 与过滤器Filter的区别 代码 Interceptor Slf4j Component public class LoginCheckInterceptor implements HandlerInterceptor {Override//目标资源方法执行前执行返回true 放行返回false 不放行public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {//1.获取urlString url req.getRequestURL().toString();//2.判断url中是否包含login如果有直接放行如果没有需要再判断if(url.contains(login)) {log.info(登录操作放行);return true;}//3.获取请求头中的令牌String jwt req.getHeader(token);//4.判断令牌是否存在若存在继续判断不存在则返回未登录信息if(!StringUtils.hasLength(jwt)) {log.info(请求头token为空返回未登录信息);Result error Result.error(NOT_LOGIN);//手动转换 对象-JSON 格式 利用阿里巴巴fastJSONString notLogin JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return false;}//令牌存在判断令牌是否合法不合法返回未登录信息try {JwtUtils.parseJwt(jwt);} catch (Exception e) {e.printStackTrace();log.info(解析令牌失败返回未登录信息);Result error Result.error(NOT_LOGIN);//手动转换 对象-JSON 格式 利用阿里巴巴fastJSONString notLogin JSONObject.toJSONString(error);resp.getWriter().write(notLogin);return false;}//放行log.info(令牌合法放行,jwt:{},jwt);return true;}Override//目标资源方法执行后执行public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}Override//视图渲染完毕后执行最后执行public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {HandlerInterceptor.super.afterCompletion(request, response, handler, ex);} } 配置类 Configuration//配置类 public class WebConfig implements WebMvcConfigurer {AutowiredLoginCheckInterceptor loginCheckInterceptor;Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginCheckInterceptor).addPathPatterns(/**).excludePathPatterns(/login);}} 异常处理 全局异常处理器 代码 exception RestControllerAdvice public class GlobalExceptionHandler {ExceptionHandler(Exception.class)public Result ex(Exception ex) {ex.printStackTrace();return Result.error(对不起操作失败请联系管理员);}} 到这里基础功能部分基本完成下面是上面代码的一些注意事项。 注意事项 1.参数及属性值都使用基本类型的包装类比如int类型用Integershort类型用Short这样传递的值为空也不会报错 2.动态SQL中查询语句后不能加分号 3.根据name查询时模糊匹配使用name like concat(%,#{name},%) 字符串拼接不然编译后#{...}变成问号出现在字符串中不起作用并且if的test判断中不仅要添加非空判断还要加上等于空值的判断and name ! 否则不输入内容点击查询会传递一个空值字符串。 事务管理 Spring事务管理 代码演示 empMapper 添加代码 Delete(delete from emp where dept_id #{deptId})void deleteByDeptId(Integer deptId); DeptService 修改删除部门代码 /*** 根据id删除部门* param id*/TransactionalOverridepublic void delete(Integer id) {deptMapper.deleteById(id);//删除该部门下的员工empMapper.deleteByDeptId(id);} 事务属性 1.回滚rollbackFor 将回滚属性改为出现任何异常都回滚 代码演示 /*** 根据id删除部门* param id*/Transactional(rollbackFor Exception.class)Overridepublic void delete(Integer id) {deptMapper.deleteById(id);//删除该部门下的员工empMapper.deleteByDeptId(id);} 2.传播行为propagation 案例 代码 建表SQL语句 CREATE TABLE dept_log (id int unsigned NOT NULL AUTO_INCREMENT COMMENT ID,create_time datetime NOT NULL COMMENT 创建时间,description varchar(300) NOT NULL COMMENT 部分解散描述,PRIMARY KEY (id) ) 日志实体类 Data AllArgsConstructor NoArgsConstructor public class DeptLog {private int id;private LocalDateTime createTime;private String description; } Controller层 删除部门部分 /*** 根据id删除部门* param id*/Transactional(rollbackFor Exception.class)Overridepublic void delete(Integer id) {try {deptMapper.deleteById(id);int i 1/0;//删除该部门下的员工empMapper.deleteByDeptId(id);} finally {DeptLog deptLog new DeptLog();deptLog.setCreateTime(LocalDateTime.now());deptLog.setDescription(删除部门,id为 id);deptLogService.insert(deptLog);}} Service层 接口 public interface DeptLogService {void insert(DeptLog log);} 实现类 Service public class DeptLogServiceImpl implements DeptLogService {AutowiredDeptLogMapper deptLogMapper;Transactional(propagation Propagation.REQUIRES_NEW)Overridepublic void insert(DeptLog log) {deptLogMapper.insert(log);}} Mapper层 Mapper public interface DeptLogMapper {Insert(insert into dept_log(create_time,description) values (#{createTime},#{description}))void insert(DeptLog log);} 使用场景 AOP(面向切面编程) 场景 基于动态代理实现最后运行的是基于目标对象代理的加强后的方法 代码 在pom.xim文件中添加依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependency 编写AOP程序 Slf4j Component Aspect//AOP类 public class TimeAspect {Around(execution(* com.han.service.*.*(..)))public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {long begin System.currentTimeMillis();Object result joinPoint.proceed();long end System.currentTimeMillis();log.info(joinPoint.getSignature() 方法的执行时间为{}ms, end - begin);return result;}} 优势 核心概念 通知类型 PointCut 通知顺序 切入点表达式 1.execution 书写建议 2.annotation 它可以通过自定义注解然后在写切入点表达式时括号中写这个自定义注解的全类名就可以把这个自定义注解注解的方法包含。 连接点 案例 准备工作 建表 -- 操作日志表 create table operate_log(id int unsigned primary key auto_increment comment ID,operate_user int unsigned comment 操作人ID,operate_time datetime comment 操作时间,class_name varchar(100) comment 操作的类名,method_name varchar(100) comment 操作的方法名,method_params varchar(1000) comment 方法参数,return_value varchar(2000) comment 返回值,cost_time bigint comment 方法执行耗时, 单位:ms ) comment 操作日志表; 创建实体类 Data AllArgsConstructor NoArgsConstructor public class OperateLog {private Integer id;private Integer operateUser;private LocalDateTime operateTime;private String className;private String methodName;private String methodParams;private String returnValue;private Long costTime; } 编码 定义Mapper Mapper public interface OperateLodMapper {Insert(insert into operate_log (operate_user,operate_time,class_name,method_name,method_params,return_value,cost_time) values (#{operateUser},#{operateTime},#{className},#{methodName},#{methodParams},#{returnValue},#{costTime}))public void insert(OperateLog log); } 定义注解 Retention(RetentionPolicy.RUNTIME) Target(ElementType.METHOD) public interface Log { } 编写AOP代码 Slf4j Component Aspect public class LogAspect {Autowiredprivate HttpServletRequest request;Autowiredprivate OperateLodMapper operateLodMapper;Around(annotation(com.han.anno.Log))public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {//获取操作用户idString jwt request.getHeader(token);MapString, Object claims JwtUtils.parseJwt(jwt);Integer operateUser (Integer) claims.get(id);//获取操作时间LocalDateTime operateTime LocalDateTime.now();//获取操作的类名String operateClass joinPoint.getTarget().getClass().getName();//获取操作的方法名String operateMethod joinPoint.getSignature().getName();//获取方法参数Object[] args joinPoint.getArgs();String methodParams Arrays.toString(args);//获取返回值(JSON字符串格式)long startTime System.currentTimeMillis();Object result joinPoint.proceed();long endTime System.currentTimeMillis();String returnValue JSONObject.toJSONString(result);//获取方法执行耗时Long costTime endTime - startTime;OperateLog operateLog new OperateLog(null,operateUser,operateTime,operateClass,operateMethod,methodParams,returnValue,costTime);operateLodMapper.insert(operateLog);log.info(AOP记录操作日志{},operateLog);return result;}} 在Controller中添加注解 EmpController Slf4j RequestMapping(/emps) RestController public class EmpController {Autowiredprivate EmpService empService;/*** 根据每页记录数和页码获取页面实体类* return*/GetMappingpublic Result getPage(RequestParam(defaultValue 1) Integer page,RequestParam(defaultValue 10) Integer pageSize,String name, Short gender,DateTimeFormat(pattern yyyy-MM-dd) LocalDate begin,DateTimeFormat(pattern yyyy-MM-dd) LocalDate end) {log.info(每页记录数{}查询页码{},pageSize,page);PageBean pb empService.getPage(page,pageSize,name,gender,begin,end);return Result.success(pb);}/*** 批量删除员工* param ids* return*/LogDeleteMapping(/{ids})public Result delete(PathVariable(ids) ListShort ids) {log.info(批量删除操作ids:{},ids);empService.delete(ids);return Result.success();}/*** 新增员工* param emp* return*/LogPostMappingpublic Result add(RequestBody Emp emp) {log.info(新增员工{},emp);empService.add(emp);return Result.success();}/*** 根据id查询员工* param id* return*/GetMapping(/{id})public Result getById(PathVariable Integer id) {log.info(查询id为:{}的员工,id);Emp emp empService.getById(id);return Result.success(emp);}/*** 修改员工* param emp* return*/LogPutMappingpublic Result update(RequestBody Emp emp) {log.info(修改员工{},emp);empService.update(emp);return Result.success();}} DeptController Slf4j RequestMapping(/depts) RestController public class DeptController {Autowiredprivate DeptService deptService;/*** 查询部门数据* return*/GetMappingpublic Result list() {log.info(查询全部部门信息);ListDept deptList deptService.list();return Result.success(deptList);}/*** 删除部门* return*/LogDeleteMapping(/{id})public Result delete(PathVariable Integer id) {log.info(删除id为 id 的部门);deptService.delete(id);return Result.success();}/*** 新增部门* param dept* return*/LogPostMappingpublic Result insert(RequestBody Dept dept) {log.info(添加部门 dept);deptService.add(dept);return Result.success();}/*** 根据id查找部门* param id* return*/GetMapping(/{id})public Result getById(PathVariable Integer id) {log.info(查询id为 id 的部门信息);Dept dept deptService.get(id);return Result.success(dept);}/*** 修改部门* param dept* return*/LogPutMappingpublic Result update(RequestBody Dept dept) {log.info(修改部门 dept);deptService.update(dept);return Result.success();}} 注意点 在获取操作用户id时要用到以下方法 SpringBoot 配置优先级 1.propertiesymlyaml 2.命令行参数Java系统属性 项目打包之后在cmd运行时设置属性或参数 3.命令行参数Java系统属性 并且在SpringBoot中直接配置Java系统属性后再使用配置文件配置那么会根据Java系统属性的配置信息配置 总结 优先级命令行参数Java系统属性propertiesymlyaml 打包方式 bean的管理 获取bean 代码演示 /*** 获得bean对象*/Autowiredprivate ApplicationContext applicationContext;Testvoid testGetBean(){//通过name获取beanDeptController bean1 (DeptController) applicationContext.getBean(deptController);System.out.println(bean1);//通过类型获取beanDeptController bean2 applicationContext.getBean(DeptController.class);System.out.println(bean2);//通过name获取bean带类型转换DeptController bean3 applicationContext.getBean(deptController, DeptController.class);System.out.println(bean3);}} 运行结果 bean的作用域 第三方bean 以xml解析类SAXReader举例 使用场景 ★SpringBoot原理 起步依赖 如果要使用web相关的依赖只需要导入spring-boot-starter-web依赖通过maven的依赖传递关于web的所有依赖都会被导入还不用担心版本兼容问题 自动配置 自动配置的原理 问题 如果我们直接在pom.xml.文件中引入第三方依赖第三方依赖中通过Component、Bean等注解定义了bean对象这种情况第三方依赖中的bean对象也是不会出现在springboot程序中的因为springboot程序通过启动类注解SpringBootApplication扫描其所在包和子包中的bean对象是扫描不到第三方依赖的。 解决方案一 ComponentScan组件扫描 启动类com.han为当前启动类所在包com.example为第三方依赖的包 ComponentScan({com.han,com.example}) ServletComponentScan SpringBootApplication public class TliasApplication {public static void main(String[] args) {SpringApplication.run(TliasApplication.class, args);}} 这种方式使用较繁琐性能低。 解决方案二 Import导入 EnableXxxx注解使用举例 SpringBootApplication源码跟踪 这里最重要的是EnableAutoConfiguration注解。 EnableAutoConfiguration 它通过封装Import注解将上图两个文件中的需要导入到IOC容器的类的全类名放入ImportSelector接口的实现类中的selectImports方法返回的字符数组以自动配置。 但是这些类并不是全部注册为IOC容器的beanSpringBoot会根据Conditional注解条件装配。 条件装配注解Conditional 1.ConditionalOnClass 2.ConditionalOnMissingBean 不指定类型和名称时默认类型指该方法返回值的类型。 使用场景默认的bean引入依赖后用户如果自定义了这个类型的bean则会导入用户自定义的如果用户没有定义就导入依赖中默认的。 3.ConditionalOnProperty 根据上述代码若在配置文件application.yml中添加配置信息name: itheima那么就会将该bean放入IOC容器中。 使用场景引入第三方变量后可以在配置文件中配置信息后才将某个类加入IOC容器。 案例自定义starter 自定义starter场景 案例需求 步骤 代码 1.新建模块aliyun-oss-spring-boot-starter只需要pom.xml文件aliyun-oss-spring-boot-autoconfigure只需要pom.xml文件和src文件夹也不需要启动类在aliyun-oss-spring-boot-starter中的pom.xml文件中引入aliyun-oss-spring-boot-autoconfigure的依赖。 aliyun-oss-spring-boot-starter ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion3.2.6/versionrelativePath/ !-- lookup parent from repository --/parentgroupIdcom.aliyun.oss/groupIdartifactIdaliyun-oss-spring-boot-starter/artifactIdversion0.0.1-SNAPSHOT/versionpropertiesjava.version17/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdcom.aliyun.oss/groupIdartifactIdaliyun-oss-spring-boot-autoconfigure/artifactIdversion0.0.1-SNAPSHOT/version/dependency/dependencies/project 2.在aliyun-oss-spring-boot-autoconfigure中的pom.xml文件中引入阿里云OSS的依赖 aliyun-oss-spring-boot-autoconfigure ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion3.2.6/versionrelativePath/ !-- lookup parent from repository --/parentgroupIdcom.aliyun.oss/groupIdartifactIdaliyun-oss-spring-boot-autoconfigure/artifactIdversion0.0.1-SNAPSHOT/versionpropertiesjava.version17/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependency!--阿里云OSS依赖--dependencygroupIdcom.aliyun.oss/groupIdartifactIdaliyun-sdk-oss/artifactIdversion3.15.1/version/dependencydependencygroupIdjavax.xml.bind/groupIdartifactIdjaxb-api/artifactIdversion2.3.1/version/dependencydependencygroupIdjavax.activation/groupIdartifactIdactivation/artifactIdversion1.1.1/version/dependency/dependencies/project 3.在aliyun-oss-spring-boot-autoconfigure中编写能够使用阿里云OSS的代码 这里要使用MultipartFile还需要引入web开发的起步依赖 ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion3.2.6/versionrelativePath/ !-- lookup parent from repository --/parentgroupIdcom.aliyun.oss/groupIdartifactIdaliyun-oss-spring-boot-autoconfigure/artifactIdversion0.0.1-SNAPSHOT/versionpropertiesjava.version17/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependency!--阿里云OSS依赖--dependencygroupIdcom.aliyun.oss/groupIdartifactIdaliyun-sdk-oss/artifactIdversion3.15.1/version/dependencydependencygroupIdjavax.xml.bind/groupIdartifactIdjaxb-api/artifactIdversion2.3.1/version/dependencydependencygroupIdjavax.activation/groupIdartifactIdactivation/artifactIdversion1.1.1/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency/dependencies/project工具类 /*** 阿里云 OSS 工具类*/ public class AliOSSUtils {private AliOSSProperties aliOSSProperties;//不能依赖注入了但是后续方法要使用aliOSSProperties对象所以定义get set方法public AliOSSProperties getAliOSSProperties() {return aliOSSProperties;}public void setAliOSSProperties(AliOSSProperties aliOSSProperties) {this.aliOSSProperties aliOSSProperties;}/*** 实现上传图片到OSS*/public String upload(MultipartFile file) throws ClientException, IOException {String endpoint aliOSSProperties.getEndpoint();String bucketName aliOSSProperties.getBucketName();InputStream inputStream file.getInputStream();// 从环境变量中获取访问凭证。运行本代码示例之前请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。EnvironmentVariableCredentialsProvider credentialsProvider CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Object完整路径例如exampleobject.txt。Object完整路径中不能包含Bucket名称。String objectName file.getOriginalFilename();String fileName UUID.randomUUID().toString() objectName.substring(objectName.lastIndexOf(.));// 填写本地文件的完整路径例如D:\\localpath\\examplefile.txt。// 如果未指定本地路径则默认从示例程序所属项目对应本地路径中上传文件。// 创建OSSClient实例OSS ossClient new OSSClientBuilder().build(endpoint, credentialsProvider);// 创建PutObjectRequest对象。PutObjectRequest putObjectRequest new PutObjectRequest(bucketName, fileName, inputStream);// 上传文件。PutObjectResult result ossClient.putObject(putObjectRequest);// 设置请求头。MapString, String headers new HashMapString, String();/*// 指定Object的存储类型。headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());// 指定ContentType。headers.put(OSSHeaders.CONTENT_TYPE, text/txt);*/// 设置用户自定义元数据。MapString, String userMetadata new HashMapString, String();/*userMetadata.put(key1,value1);userMetadata.put(key2,value2);*/URL signedUrl null;// 指定生成的签名URL过期时间单位为毫秒。本示例以设置过期时间为1小时为例。Date expiration new Date(new Date().getTime() 3600 * 1000L);// 生成签名URL。GeneratePresignedUrlRequest request new GeneratePresignedUrlRequest(bucketName, fileName);// 设置过期时间。request.setExpiration(expiration);// 将请求头加入到request中。request.setHeaders(headers);// 添加用户自定义元数据。request.setUserMetadata(userMetadata);// 通过HTTP PUT请求生成签名URL。signedUrl ossClient.generatePresignedUrl(request);// 返回签名URL。ossClient.shutdown();return signedUrl.toString().split(\\?)[0];}} 认证信息存储类 ConfigurationProperties(prefix aliyun.oss)//用于验证配置文件中以aliyun.oss为前缀的属性 public class AliOSSProperties {private String endpoint;private String bucketName;public String getEndpoint() {return endpoint;}public void setEndpoint(String endpoint) {this.endpoint endpoint;}public String getBucketName() {return bucketName;}public void setBucketName(String bucketName) {this.bucketName bucketName;}} 4.定义自动配置类AliOSSAutoConfiguration Configuration//配置类 EnableConfigurationProperties(AliOSSProperties.class)//将AliOSSProperties类bean对象放入IOC容器 public class AliOSSAutoConfiguration {Beanpublic AliOSSUtils aliOSSUtils(AliOSSProperties aliOSSProperties){//需要注入某个对象直接在方法形参中指定AliOSSUtils aliOSSUtils new AliOSSUtils();aliOSSUtils.setAliOSSProperties(aliOSSProperties);return aliOSSUtils;}} 5.定义自动配置文件在resource目录下创建文件夹META-INF/spring下的文件org.springframework.boot.autoconfigure.AutoConfiguration 并存入配置类的全类名 com.aliyun.oss.AliOSSAutoConfiguration 测试案例 新建模块配置阿里云OSS信息 application.yml: #阿里云OSS配置 aliyun:oss:endpoint: https://oss-cn-beijing.aliyuncs.combucketName: web-talias-test 引入自定义的依赖只需要引入starter pom.xml: ?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion3.2.6/versionrelativePath/ !-- lookup parent from repository --/parentgroupIdcom.han/groupIdartifactIdspringboot-autoconfiguration-test/artifactIdversion0.0.1-SNAPSHOT/versionnamespringboot-autoconfiguration-test/namedescriptionspringboot-autoconfiguration-test/descriptionpropertiesjava.version17/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdcom.aliyun.oss/groupIdartifactIdaliyun-oss-spring-boot-starter/artifactIdversion0.0.1-SNAPSHOT/version/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build/project 编写Controller RestController public class UploadController {Autowiredprivate AliOSSUtils aliOSSUtils;PostMapping(/upload)public String upload(MultipartFile image) throws Exception {String url aliOSSUtils.upload(image);return url;}} Postman测试 浏览器打开网址可正常下载显示。 框架总结 SpringMVC Spring frameworkSpring Mybatis SSM框架 SpringMVC属于Spring框架是Spring框架当中提供的web开发模块是用来简化原始的servelet程序的开发的。 基于传统的SSM框架开发进行整合开发是比较繁琐的效率也较低所以目前的企业项目开发当中基本上都是基于SpringBoot进行项目开发的。
http://www.dnsts.com.cn/news/182517.html

相关文章:

  • 网站关键词seo排名广州网站制作到诺然
  • 门户网站的流程电话卡代理平台
  • 网站建设找业主签字模板济南富库网络技术有限公司
  • 微信公众号怎么做微网站吗专业手机移动网站设计
  • 东莞企业网站找谁成都洛羽网络科技有限公司
  • 深圳华维网站建设百度竞价推广收费
  • 合肥建设工会网站seo的中文含义是什么
  • 制作个人网站的软件试玩网站开发
  • 做任务赚话费的网站营销型外贸网站广州
  • 如何做网站的实时画面58同城免费发布信息
  • PHP MySQL 网站开发实例网片图片和价格
  • 网站底部关键词uniapp小程序开发教程
  • 网站建设方案书 百度文库成都住建局官网住建扬尘监测
  • 杨凌做网站的京东网站建设目标是什么
  • 医美网站建设个人网站能否备案
  • 网页界面设计作品推荐SEO优化网站建设价格
  • 我想做个卷帘门网站怎么做如何建设属于自己的网站
  • 在微信上做彩票网站吗wordpress 经典博客主题
  • 怎样给网站做优化做护肤品好的网站好
  • 成都比较好的网站设计公司东莞推广优化关键词优化
  • 设计网站公司有哪些永久免费erp
  • 官方网站建设 都来磐石网络网站增加关键词
  • 大连网站哪家做的好?wordpress用户角色插件
  • 网站vip功能怎么实现logo在线设计生成器标智客
  • 网站开发安卓手机怎么搭建网页
  • 网站管理员登陆后缀牛商网做的包装盒网站
  • dede网站建设的个人总结电子商务网站开发人员
  • 做纺织外贸网站绍兴网站推广排名
  • 响应式潍坊网站建设网站备案主体域名
  • 网站上的通话功能怎么做中国建设会计网站