学习项目实战中的知识点(更新中)

小知识点

1.Mapper主键返回

//增加数据,并返回id值
@Options(useGeneratedKeys = true,keyProperty = "id")

2.Redis常用命令

2.1 开启Redis服务器
redis-server.exe  redis.windows.conf
2.2 客户端连接命令
redis-cli.exe  -h  ip地址(localhost)  -p  端口号(6379)  -a  密码(123456)
2.3 字符串指令
SET key value       			//设置指定的key值
GET key                 		//获取指定的key值
SETEX  key  seconds  values  	//获取指定的key值,并将key的过期时间设为seconds秒
SETNX  key  values  			//只有在key不存在时设置key的值
2.4 哈希操作命令
HSET key field value  	//将哈希表 key 中的字段 field 的值设为 value
HGET key field          //获取哈希表中的指定的field字段
HDEL key field          //删除存储在哈希表中的指定字段
HKEYS key               //获取哈希表中所有的字段
HVALS key               //获取哈希表中所有的值
2.5 列表操作命令
LPUSH key value1[value2]    //将一个或多个值插入到列表头部
LRANGE key start stop       //获取列表指定范围内的元素
RPOP key                    //移除并获取列表最后一个元素
LLEN  key                   //获取列表的长度
2.6 集合操作命令
SADD  key   member1  [member2]     //给集合表key字段的值设为member
SMEMBERS key                       //返回集合中的所有成员
SCARD         key                  //获取集合的成员数
SINTER        key1[key2]           //返回给定所有集合的交集
SUNION      key1[key2]             //返回给定所有集合的并集
SREM    key  member1[member2]      //删除指定的成员  
2.7 有序集合操作命令
ZADD key score1 member1[score2  member2...]     //向有序集合添加一个或多个成员
ZRANGE  key  start  stop  [WITHSCORES]     		//通过索引区间返回有序集合中指定区间内的成员
ZINCRBY key  increment  member          		//有序集合中对指定成员的分数加上增量 increment
ZREM key  member                                //移除有序集合中的一个或多个成员
2.8 通用命令
KEYS pattern      //查询所有符合给定模式的键(key)
EXISTS  key       //检查给定 key 是否存在
TYPE     key      //返回 key 所储存的值的类型
DEL       key     //该命令用于在 key 存在是删除 key

3.使用spring集成的Spring Cache

3.1 关于注解

在这里插入图片描述

3.2 在启动类配置redis

@EnableCaching  //开启缓存注解功能

3.3 在方法上写对应注解

先查再插

在这里插入图片描述

/**
* 数据库优化:
*      先查询缓存,如果有缓存则不进入方法体直接返回redis缓存数据
*      如果没有缓存则执行方法,并把返回值放入缓存
* 注意:
*      真正redis的key是userCache::key  --->>   userCache::101
*/
@Cacheable(cacheNames = "userCache",key = "#id")

删除单个

//清理单个缓存
@CacheEvict(cacheNames = "userCache",key = "#id")

删除全部

//清理全部缓存
@CacheEvict(cacheNames = "userCache",allEntries = true)

存入redis

//存入redis
@CachePut(cacheNames = "userCache",key = "#user.id")//形参 对象导航
//    @CachePut(cacheNames = "userCache",key = "#result.id")//返回值 对象导航
//    @CachePut(cacheNames = "userCache",key = "#p0.id")//第一个参数 对象导航
//    @CachePut(cacheNames = "userCache",key = "#a0.id")//第一个参数 对象导航
//    @CachePut(cacheNames = "userCache",key = "#root.args[0].id")//第一个参数 对象导航

4. 公共字段自动填充

4.1 问题分析

处理每个类的重复代码,可以使用切面类进行自动填充

4.2 步骤

4.2.1 步骤一

自定义注解 AutoFill

package com.sky.annotation;

import com.sky.enumeration.OperationType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义注解,用于标识某个方法需要进行功能字段自动填充处理
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    //数据库操作类型:UPDATE INSERT
    OperationType value();
}
4.2.2 步骤二

自定义切面 AutoFillAspect

package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 自定义切面,实现公共字段自动填充处理逻辑
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    /**
     * 切入点
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut(){}

    /**
     * 前置通知,在通知中进行公共字段的赋值
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint){
        log.info("开始进行公共字段自动填充...");

        //获取到当前被拦截的方法上的数据库操作类型
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();//方法签名对象
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获得方法上的注解对象
        OperationType operationType = autoFill.value();//获得数据库操作类型

        //获取到当前被拦截的方法的参数--实体对象
        Object[] args = joinPoint.getArgs();
        if(args == null || args.length == 0){
            return;
        }

        Object entity = args[0];

        //准备赋值的数据
        LocalDateTime now = LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();

        //根据当前不同的操作类型,为对应的属性通过反射来赋值
        if(operationType == OperationType.INSERT){
            //为4个公共字段赋值
            try {
                Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                //通过反射为对象属性赋值
                setCreateTime.invoke(entity,now);
                setCreateUser.invoke(entity,currentId);
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else if(operationType == OperationType.UPDATE){
            //为2个公共字段赋值
            try {
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                //通过反射为对象属性赋值
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
4.2.3 步骤三

在Mapper接口的方法上加入 AutoFill 注解

写上autoFillPointCut注解并声明类型即可使用自动装配


1. HttpClient

1.1 用法

引入依赖

<dependency>    	
	<groupId>org.apache.httpcomponents</groupId>    									  	  <artifactId>httpclient</artifactId>    
	<version>4.5.13</version>
</dependency>

发送请求步骤:
创建HttpClient对象
创建Http请求对象
调用HttpClient的execute方法发送请求

1.2 java代码

GET方式请求

//http客户端对象,可以发送http请求
CloseableHttpClient httpClient = HttpClients.createDefault();
//构造Get方式请求
HttpGet httpGet = new HttpGet("http://localhost:8080/user/shop/status");
//发送请求
CloseableHttpResponse response = httpClient.execute(httpGet);
//http响应码
int statusCode = response.getStatusLine().getStatusCode();
//http响应体
HttpEntity entity = response.getEntity();
//将响应体转为String字符串
String body = EntityUtils.toString(entity);
System.out.println(body);
//关闭资源
response.close();
httpClient.close();

POST方式请求

CloseableHttpClient httpClient = HttpClients.createDefault();
//Post方式请求
HttpPost httpPost = new HttpPost("http://localhost:8080/admin/employee/login");
//构造json数据
JSONObject jsonObject = new JSONObject();
jsonObject.put("username","admin");
jsonObject.put("password", "123456");
//构造请求体
StringEntity stringEntity = new StringEntity(jsonObject.toString());
//设置请求编码
stringEntity.setContentEncoding("utf-8");
//设置数据类型
stringEntity.setContentType("application/json");
//设置当前Post请求的请求体httpPost.setEntity(stringEntity);
//发送请求
CloseableHttpResponse response = httpClient.execute(httpPost);
//http响应码
int statusCode = response.getStatusLine().getStatusCode();
//http响应体
HttpEntity entity = response.getEntity();
//将响应体转为String字符串
String body = EntityUtils.toString(entity);
System.out.println(body);
//关闭资源
response.close();
httpClient.close();

2. 微信小程序开发

2.1 流程图

微信登录流程图

2.2 全部流程

2.2.1 小程序

  1. 获取授权码

    <view>
        <button bindtap="wxLogin" type="warn">微信登录</button>
        授权码:{{code}}
    </view>
    
  2. js获得到该用户的授权码,每点击一次生成不同的授权码,将授权码发送到服务器,调用wx.request()发送请求并携带code

    Page({
        code:'',
    	},
    	//微信登录,获取微信用户的授权码
      	wxLogin(){
        	wx.login({
          	success : (res) => {
            	console.log(res.code)
            	this.setData({
              	code:res.code
            	})
          		}
        	})
      	},
    }
    

2.2.2 后端

  1. 创建UserController类,Login方法,配置路径为"/user/user/login",在controller类中获得微信端的授权码code,传到service,传回的以user类封装

    User user = userService.wxLogin(userLoginDTO);
    
  2. 将创建者的appid和secret写入yml文件,通过@ConfigurationProperties自动配置到WeChatProperties类

    • yml文件
    sky:
    	wechat:
        	appid: wxcb56ecdf2d73af26
        	secret: d64885fb53145ea3ff5d386e44f0a65f
    
    • WeChatProperties配置类
    @Component
    @ConfigurationProperties(prefix = "sky.wechat")
    @Data
    public class WeChatProperties {
    	//可通过yml赋值
        private String appid; //小程序的appid
        private String secret; //小程序的秘钥
        
        private String mchid; //商户号
        private String mchSerialNo; //商户API证书的证书序列号
        private String privateKeyFilePath; //商户私钥文件
        private String apiV3Key; //证书解密的密钥
        private String weChatPayCertFilePath; //平台证书
        private String notifyUrl; //支付成功的回调地址
        private String refundNotifyUrl; //退款成功的回调地址
    }
    

3.配置为微信用户生成jwt令牌时使用的配置项:

sky:
  jwt:
    # 设置jwt签名加密时使用的秘钥
    admin-secret-key: itcast
    # 设置jwt过期时间
    admin-ttl: 7200000
    # 设置前端传递过来的令牌名称
    admin-token-name: token
    user-secret-key: itheima
    user-ttl: 7200000
    user-token-name: authentication

4.jwt用户配置类

@Component
@ConfigurationProperties(prefix = "sky.jwt")
@Data
public class JwtProperties {
    /**
     * 用户端微信用户生成jwt令牌相关配置
     */
    private String userSecretKey;
    private long userTtl;
    private String userTokenName;
}

5.通过微信第三方接口获得openId(唯一)

链接: https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code

private String getOpenId(String code){
        //调用微信接口服务,获得当前微信用户的openid
        Map<String, String> map = new HashMap<>();
        //微信用户授权码
        map.put("js_code",code);
        //appid
        map.put("appid",weChatProperties.getAppid());
        //secret
        map.put("secret",weChatProperties.getSecret());
        //固定字符串,写死
        map.put("grant_type","authorization_code");
        //使用get请求 --- 发送到微信第三方接口,回的json有包括openid
    	//WX_LOGIN  -->  https://api.weixin.qq.com/sns/jscode2session
        String json = HttpClientUtil.doGet(WX_LOGIN, map);
        //将拿到的json字符串抓换成json,再拿到openId值
        JSONObject jsonObject = JSON.parseObject(json);
        String openid = jsonObject.getString("openid");
        return openid;
    }

6.将openId进行一个判断,如果为空抛出一个登录异常

拿到了则通过拿到的openId去数据库查询,如果查到了返回用户信息,没查到则插入新数据进数据库

public User wxLogin(UserLoginDTO userLoginDTO) {
        String openid = getOpenId(userLoginDTO.getCode());
        //判断openid是否为空,如果为空表示登陆失败,抛出业务异常
        if (openid == null){
            throw new LoginFailedException(MessageConstant.LOGIN_FAILED);
        }
        //判断当前用户是否为新用户
        User user = userMapper.getByOpenId(openid);
        if (user == null){
            //如果是新用户,自动完成注册
            user = User.builder().openid(openid).createTime(LocalDateTime.now()).build();
            //执行新增]
            userMapper.addUser(user);
        }
        //返回这个用户对象
        return user;
    }

7.将反上来的user的id放入到Jwt令牌生成,把id、openid和token返回到前端

Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.USER_ID, user.getId());
        String jwt = JwtUtil.createJWT(jwtProperties.getUserSecretKey(),
                                       jwtProperties.getUserTtl(),
                                       claims);

8.设置拦截器

@Component
@Slf4j
public class JwtTokenUserInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtProperties jwtProperties;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断是否是controller方法
        if (!(handler instanceof HandlerMethod)){
            //不是controller方法就放行
            return true;
        }
        try {
            //拿到token的jwt令牌
            String jwt = request.getHeader(jwtProperties.getUserTokenName());
            log.info("用户jwt校验{}",jwt);
            //通过工具类解析jwt
            Map<String, Object> claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), jwt);
            //得到jwt中的userId
            Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());
            log.info("当前用户id{}",userId);
            //为当前线程存入userid
            BaseContext.setCurrentId(userId);
            return true;
        } catch (Exception e) {
            //jwt校验有错,返回404
            response.setStatus(404);
            return false;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //最后清除当前线程存放的值
        BaseContext.removeCurrentId();
    }
}

9.在WebMvcConfiguration配置类中注册拦截器

由于想要客户在登录时也要看到当前店铺是否营业状态,这里排除掉状态的请求路径

//配置user的拦截器
        registry.addInterceptor(jwtTokenUserInterceptor)
                .addPathPatterns("/user/**")
                .excludePathPatterns("/user/user/login")
                .excludePathPatterns("/user/shop/status");

3. 防止非本地ip(127.0.0.1)入侵系统

3.1 在nginx中更改反向代理的配置文件

location /api/ {
    # 反向代理
    proxy_pass   http://localhost:8080/admin/;



    # 获取客户端(client)的真实域名和端口号;
    proxy_set_header Host $http_host;

    #将用户的真实IP存放到X-Real-IP这个变量中
    # 后端使用HttpServletRequest request.getHeader("X-Real-IP") 获取真实ip
    proxy_set_header X-Real-IP $remote_addr;

    # 也是获取客户端真实 IP,如果有多层代理时会获取客户端真实 IP 及每层代理服务器的 IP
    # request.getHeader("X-Forwarded-For");
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    #获取客户端的真实协议(如 http、https)
    proxy_set_header X-Forwarded-Proto $scheme;
}

3.2 过滤器代码编写

//获取到真实ip地址
String ip = request.getHeader("x-forwarded-for");
log.info("ip:{}", ip);
//比对是否是本机地址访问的
if (!ip.equals("127.0.0.1")) {
    log.error("!!!有人入侵!!!-------ip:{}", ip);
    return false;
}

3.3 登录controller类中代码编写

  1. 将访问者ip地址存到jwt中

    //获得访问网站的ip地址
    String ip = request.getHeader("x-forwarded-for");
    //登录成功后,生成jwt令牌
    Map<String, Object> claims = new HashMap<>();
    claims.put(JwtClaimsConstant.EMP_ID, employee.getId());
    claims.put("ip",ip);
    String token = JwtUtil.createJWT(
        jwtProperties.getAdminSecretKey(),
        jwtProperties.getAdminTtl(),
        claims);  
    
  2. 在过滤器校验jwt的ip地址

    JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token); String
    loginIp = (String) claims.get("ip"); if
    (!loginIp.equals("127.0.0.1")){    
       log.error("!!!有人入侵!!!-------ip:{}", ip);    
       return false; }
        ```
    
    
  3. 回到控制类编写判断代码

    if(!ip.equals("127.0.0.1")){
        if (ip.equals("192.168.84.153")){
            //页面返回错误信息
           return Result.error("小小***,快爬!!!");
        }
        if (ip.equals("192.168.84.166"))
            return Result.error("小小***,快爬!!!");
        return Result.error("想悄咪咪进爷系统?快爬!!!");
    }
    

4. 微信支付

整体流程

支付流程图

  1. 用户在微信端发起支付请求
  2. 后台生成订单,随后请求微信端的预支付接口,拿到预支付标识码
  3. 把预支付标识码配合appid、时间戳和随机数(数据安全)打成一个包发送到前端
  4. 前端展示给用户一个支付按钮,确定则直接发送到微信后端接口随后微信端给前端和后端返回数据,在前端返回支付结果,后端根据设置好的接口调用其以去解析微信的数据包,在数据库修改订单信息

5. Spring Task

处理定时任务

5.1 Cron表达式

cron表达式其实就是一个字符串,通过cron表达式可以定义任务触发的时间

**构成规则:**分为6或7个域,由空格分隔开,每个域代表一个含义

每个域的含义分别为:秒、分钟、小时、日、月、周、年(可选)

举例:

2022年10月12日上午9点整 对应的cron表达式为:0 0 9 12 10 ? 2022

在这里插入图片描述

说明:一般的值不同时设置,其中一个设置,另一个用?表示。

**比如:**描述2月份的最后一天,最后一天具体是几号呢?可能是28号,也有可能是29号,所以就不能写具体数字。

为了描述这些信息,提供一些特殊的字符。这些具体的细节,我们就不用自己去手写,因为这个cron表达式,它其实有在线生成器。

cron表达式在线生成器:https://cron.qqe2.com/

在这里插入图片描述

可以直接在这个网站上面,只要根据自己的要求去生成corn表达式即可。所以一般就不用自己去编写这个表达式。

通配符:

* 表示所有值;

? 表示未说明的值,即不关心它为何值;

- 表示一个指定的范围;

, 表示附加一个可能值;

/ 符号前表示开始时间,符号后表示每次递增的值;

cron表达式案例:

*/5 * * * * ? 每隔5秒执行一次

0 */1 * * * ? 每隔1分钟执行一次

0 0 5-15 * * ? 每天5-15点整点触发

0 0/3 * * * ? 每三分钟触发一次

0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发

0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发

0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发

0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时

0 0 10,14,16 * * ? 每天上午10点,下午2点,4点

5.2 操作步骤

  1. 导入maven坐标spring-context(已关联到spring-boot-starter)

  2. 启动类注解

    @EnableScheduling   //开启spring task定时调度服务
    
  3. Task类注解

     @Component
     public class OrderTask {
       	@Scheduled(cron = "0 0/1 * * * ?") //每分钟触发一次
         public void processTimeoutOrder(){
             /**
              * 需要定时任务的代码块
           */
         }
    }
    

6. WebSocker

6.1 介绍

WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接, 并进行双向数据传输。

HTTP协议和WebSocket协议对比:

  • HTTP是短连接
  • WebSocket是长连接
  • HTTP通信是单向的,基于请求响应模式
  • WebSocket支持双向通信
  • HTTP和WebSocket底层都是TCP连接

在这里插入图片描述

6.2 操作流程

1). 导入maven坐标

在sky-server模块pom.xml中已定义

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2). 定义WebSocket服务端组件(资料中已提供)

直接导入到sky-server模块即可

package com.sky.websocket;

import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * WebSocket服务
 */
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {

    //存放会话对象
    private static Map<String, Session> sessionMap = new HashMap();

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        System.out.println("客户端:" + sid + "建立连接");
        sessionMap.put(sid, session);
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, @PathParam("sid") String sid) {
        System.out.println("收到来自客户端:" + sid + "的信息:" + message);
    }

    /**
     * 连接关闭调用的方法
     *
     * @param sid
     */
    @OnClose
    public void onClose(@PathParam("sid") String sid) {
        System.out.println("连接断开:" + sid);
        sessionMap.remove(sid);
    }

    /**
     * 群发
     *
     * @param message
     */
    public void sendToAllClient(String message) {
        Collection<Session> sessions = sessionMap.values();
        for (Session session : sessions) {
            try {
                //服务器向客户端发送消息
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

3). 定义配置类,注册WebSocket的服务端组件(从资料中直接导入即可)

package com.sky.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * WebSocket配置类,用于注册WebSocket的Bean
 */
@Configuration
public class WebSocketConfiguration {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

7. 报表导出Apache POI

7.1 介绍

Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是,我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。
一般情况下,POI 都是用于操作 Excel 文件。

POI操作大致流程

7.2 入门案例

Apache POI既可以将数据写入Excel文件,也可以读取Excel文件中的数据,接下来分别进行实现。

Apache POI的maven坐标:(项目中已导入)

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.16</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.16</version>
</dependency>
7.2.1 将数据写入Excel文件

1). 代码开发

package com.sky.test;

import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class POITest {

    /**
     * 基于POI向Excel文件写入数据
     * @throws Exception
     */
    public static void write() throws Exception{
        //在内存中创建一个Excel文件对象
        XSSFWorkbook excel = new XSSFWorkbook();
        //创建Sheet页
        XSSFSheet sheet = excel.createSheet("itcast");

        //在Sheet页中创建行,0表示第1行
        XSSFRow row1 = sheet.createRow(0);
        //创建单元格并在单元格中设置值,单元格编号也是从0开始,1表示第2个单元格
        row1.createCell(1).setCellValue("姓名");
        row1.createCell(2).setCellValue("城市");

        XSSFRow row2 = sheet.createRow(1);
        row2.createCell(1).setCellValue("张三");
        row2.createCell(2).setCellValue("北京");

        XSSFRow row3 = sheet.createRow(2);
        row3.createCell(1).setCellValue("李四");
        row3.createCell(2).setCellValue("上海");

        FileOutputStream out = new FileOutputStream(new File("D:\\itcast.xlsx"));
        //通过输出流将内存中的Excel文件写入到磁盘上
        excel.write(out);

        //关闭资源
        out.flush();
        out.close();
        excel.close();
    }
    public static void main(String[] args) throws Exception {
        write();
    }
}

2). 实现效果

在D盘中生成itcast.xlsx文件,创建名称为itcast的Sheet页,同时将内容成功写入。

把数据写入表格

7.2.2 读取Excel文件中的数据

1). 代码开发

package com.sky.test;

import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class POITest {
    /**
     * 基于POI读取Excel文件
     * @throws Exception
     */
    public static void read() throws Exception{
        FileInputStream in = new FileInputStream(new File("D:\\itcast.xlsx"));
        //通过输入流读取指定的Excel文件
        XSSFWorkbook excel = new XSSFWorkbook(in);
        //获取Excel文件的第1个Sheet页
        XSSFSheet sheet = excel.getSheetAt(0);

        //获取Sheet页中的最后一行的行号
        int lastRowNum = sheet.getLastRowNum();

        for (int i = 0; i <= lastRowNum; i++) {
            //获取Sheet页中的行
            XSSFRow titleRow = sheet.getRow(i);
            //获取行的第2个单元格
            XSSFCell cell1 = titleRow.getCell(1);
            //获取单元格中的文本内容
            String cellValue1 = cell1.getStringCellValue();
            //获取行的第3个单元格
            XSSFCell cell2 = titleRow.getCell(2);
            //获取单元格中的文本内容
            String cellValue2 = cell2.getStringCellValue();

            System.out.println(cellValue1 + " " +cellValue2);
        }

        //关闭资源
        in.close();
        excel.close();
    }

    public static void main(String[] args) throws Exception {
        read();
    }
}

2). 实现效果

将itcast.xlsx文件中的数据进行读取

读取表格数据

注:导出到浏览器以供下载

public void exportBusinessData(HttpServletResponse response) {
    /**
     * 报表相关操作
     */
    
    //得到模板文件流
    InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
    //基于提供好的模板文件创建一个新的Excel表格对象
    XSSFWorkbook excel = new XSSFWorkbook(inputStream);
    
    
	//通过输出流将文件下载到客户端浏览器中
	ServletOutputStream out = response.getOutputStream();
	excel.write(out);
}
.getCell(1);
            //获取单元格中的文本内容
            String cellValue1 = cell1.getStringCellValue();
            //获取行的第3个单元格
            XSSFCell cell2 = titleRow.getCell(2);
            //获取单元格中的文本内容
            String cellValue2 = cell2.getStringCellValue();

            System.out.println(cellValue1 + " " +cellValue2);
        }

        //关闭资源
        in.close();
        excel.close();
    }

    public static void main(String[] args) throws Exception {
        read();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值