自动生成带昵称的头像(仿照钉钉头像)

本文介绍了一种根据用户姓名自动生成个性化头像的方法,通过截取姓名的特定部分并使用随机颜色背景,结合中文和英文名字的不同处理方式,最终生成具有圆角的图片头像。

很多场合都会出现默认头像,比如刚注册的账户还未自定义头像,显示就是默认头像,这种头像一般都很丑,想到钉钉那种风格还挺特别的,仿照写一个。

废话不多说,直接上代码。

import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
 
 
/**
 * 根据姓名创建图片
 */
public class CreateNamePicture {
    /**
     * @throws IOException
     * @throws
     **/
    public static void main(String[] args) throws IOException {
        String name = "张三";
        generateImg(name, "/Users/xingchenge/Desktop/temp", name);
    }
 
 
    /**
     * 绘制字体头像
     * 如果是英文名,只显示首字母大写
     * 如果是中文名,只显示最后两个字
     * @param name
     * @param outputPath
     * @param outputName
     * @throws IOException
     */
    public static void generateImg(String name, String outputPath, String outputName)
            throws IOException {
        int width = 100;
        int height = 100;
        int nameLen = name.length();
        String nameWritten;
        // 如果用户输入的姓名少于等于2个字符,不用截取
        if (nameLen <= 2) {
            nameWritten = name;
        } else {
            // 如果用户输入的姓名大于等于3个字符,截取后面两位
            String first = name.substring(0, 1);
            if (isChinese(first)) {
                // 截取倒数两位汉字
                nameWritten = name.substring(nameLen - 2);
            } else {
                // 截取前面的两个英文字母
                nameWritten = name.substring(0, 2).toUpperCase();
            }
        }
 
        String filename = outputPath + File.separator + outputName + ".jpg";
        File file = new File(filename);
        //Font font = new Font("微软雅黑", Font.PLAIN, 30);
 
        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
 
        Graphics2D g2 = (Graphics2D) bi.getGraphics();
        g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
 
        g2.setBackground(getRandomColor());
 
        g2.clearRect(0, 0, width, height);
 
        g2.setPaint(Color.WHITE);
 
 
        Font font = null;
        // 两个字及以上
        if(nameWritten.length() >= 2) {
            font = new Font("微软雅黑", Font.PLAIN, 30);
            g2.setFont(font);
 
            String firstWritten = nameWritten.substring(0, 1);
            String secondWritten = nameWritten.substring(1, 2);
 
            // 两个中文 如 张三
            if (isChinese(firstWritten) && isChinese(secondWritten)) {
                g2.drawString(nameWritten, 20, 60);
            }
            // 首中次英 如 张S
            else if (isChinese(firstWritten) && !isChinese(secondWritten)) {
                g2.drawString(nameWritten, 27, 60);
                
            } 
            // 首英,如 ZS
            else {
                nameWritten = nameWritten.substring(0,1);
            }
 
        }
        // 一个字
        if(nameWritten.length() ==1) {
            // 中文
            if(isChinese(nameWritten)) {
                font = new Font("微软雅黑", Font.PLAIN, 50);
                g2.setFont(font);
                g2.drawString(nameWritten, 25, 70);
            }
            // 英文
            else {
                font = new Font("微软雅黑", Font.PLAIN, 55);
                g2.setFont(font);
                g2.drawString(nameWritten.toUpperCase(), 33, 67);
            }
 
        }
 
        BufferedImage rounded = makeRoundedCorner(bi, 99);
        ImageIO.write(rounded, "png", file);
    }
 
 
    /**
     * 判断字符串是否为中文
     * @param str
     * @return
     */
    public static boolean isChinese(String str) {
        String regEx = "[\\u4e00-\\u9fa5]+";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        if (m.find())
            return true;
        else
            return false;
    }
 
    /**
     * 获得随机颜色
     * @return
     */
    private static Color getRandomColor() {
        String[] beautifulColors =
                new String[]{"232,221,203", "205,179,128", "3,101,100", "3,54,73", "3,22,52",
                        "237,222,139", "251,178,23", "96,143,159", "1,77,103", "254,67,101", "252,157,154",
                        "249,205,173", "200,200,169", "131,175,155", "229,187,129", "161,23,21", "34,8,7",
                        "118,77,57", "17,63,61", "60,79,57", "95,92,51", "179,214,110", "248,147,29",
                        "227,160,93", "178,190,126", "114,111,238", "56,13,49", "89,61,67", "250,218,141",
                        "3,38,58", "179,168,150", "222,125,44", "20,68,106", "130,57,53", "137,190,178",
                        "201,186,131", "222,211,140", "222,156,83", "23,44,60", "39,72,98", "153,80,84",
                        "217,104,49", "230,179,61", "174,221,129", "107,194,53", "6,128,67", "38,157,128",
                        "178,200,187", "69,137,148", "117,121,71", "114,83,52", "87,105,60", "82,75,46",
                        "171,92,37", "100,107,48", "98,65,24", "54,37,17", "137,157,192", "250,227,113",
                        "29,131,8", "220,87,18", "29,191,151", "35,235,185", "213,26,33", "160,191,124",
                        "101,147,74", "64,116,52", "255,150,128", "255,94,72", "38,188,213", "167,220,224",
                        "1,165,175", "179,214,110", "248,147,29", "230,155,3", "209,73,78", "62,188,202",
                        "224,160,158", "161,47,47", "0,90,171", "107,194,53", "174,221,129", "6,128,67",
                        "38,157,128", "201,138,131", "220,162,151", "137,157,192", "175,215,237", "92,167,186",
                        "255,66,93", "147,224,255", "247,68,97", "185,227,217"};
        int len = beautifulColors.length;
        Random random = new Random();
        String[] color = beautifulColors[random.nextInt(len)].split(",");
        return new Color(Integer.parseInt(color[0]), Integer.parseInt(color[1]),
                Integer.parseInt(color[2]));
    }
 
 
    /**
     * 图片做圆角处理
     * @param image
     * @param cornerRadius
     * @return
     */
    public static BufferedImage makeRoundedCorner(BufferedImage image, int cornerRadius){
        int w = image.getWidth();
        int h = image.getHeight();
        BufferedImage output = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = output.createGraphics();
        g2.setComposite(AlphaComposite.Src);
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(Color.WHITE);
        g2.fill(new RoundRectangle2D.Float(0, 0, w, h, cornerRadius, cornerRadius));
        g2.setComposite(AlphaComposite.SrcAtop);
        g2.drawImage(image, 0, 0, null);
        g2.dispose();
        return output;
    }
 
}

 

<think>好的,用户想了解如何用Java实现类似钉钉的工作流功能,需要一个开发教程。首先,我需要回顾一下之前提供的参考信息,特别是关于AntFlow工作流引擎的部分,因为用户提到了钉钉的工作流,而AntFlow是开源的,可能相关。引用[1]、[2]、[3]都提到了AntFlow的设计背景、技术亮点和应用场景,这些信息可以用来指导回答。 首先,用户的需求是开发一个类似钉钉的工作流引擎,可能需要包括流程设计器、流程引擎核心、节点处理逻辑、与业务系统的集成等部分。根据引用[3],AntFlow使用Java和Spring Boot构建,支持MySQL和TiDB,前端用Vue3和elementplus,这些技术栈可以作为参考。 接下来,我需要分步骤解释如何实现。第一步是设计流程模型,可能需要使用BPMN或者自定义的JSON结构。引用[3]提到AntFlow有简洁的流程设计器,所以可能需要设计一个类似的模型结构。 第二步是流程引擎核心开发,需要状态机驱动流程流转,处理节点类型如开始、审批、条件分支等。引用[2]中提到AntFlow最初是为了快速开发而定制,所以可能需要一个轻量级的状态机实现。 第三步是节点处理逻辑,比如审批节点可能需要集成用户体系,条件节点需要解析表达式。引用[1]提到开发者只需要关注业务CRUD,所以引擎需要提供扩展点,让用户自定义逻辑。 第四步是流程设计器,可以使用现成的库如bpmn-js或者自定义前端组件。引用[3]提到AntFlow的设计器用户友好,所以可能需要推荐一些前端库。 第五步是持久化与事务管理,需要将流程实例状态存储到数据库,并处理事务。引用[3]提到支持MySQL,所以可以建议使用Spring Data JPA或MyBatis。 第六步是集成业务系统,通过REST API或消息队列。引用[3]提到AntFlow有内置API,所以需要提供接口供业务系统调用。 代码示例部分,可以给出一个简单的状态机实现和审批节点处理的示例,参考引用中的Python示例,但这里需要用Java。例如,使用Spring Boot的RestController处理审批请求。 可能的相关问题需要包括技术选型对比、性能优化、与企业用户系统集成、前端设计器实现等,这些都能从引用中找到线索,比如引用[2]提到了Activiti、Flowable等,可以对比它们与自定义引擎的优劣。 需要确保回答符合系统级指令:行内公式用$,独立公式单独成段,正确的中文和LaTeX,生成相关问题。同时,引用需要自然添加,比如在提到流程设计器时引用[^1],提到快速开发时引用[^2],技术架构时引用[^3]。 最后,检查是否有遗漏的要点,比如事务管理、扩展性、社区支持等,确保回答结构清晰,步骤明确,帮助用户逐步实现工作流引擎。</think>以下是如何使用Java实现类似钉钉工作流引擎的开发指南,结合开源项目AntFlow的设计思路: ### 一、核心架构设计 1. **流程模型定义** - 使用JSON或XML定义流程模板,包含节点类型(审批/条件/通知)、流转规则等 - 示例结构: ```json { "processId": "LEAVE_APPROVAL", "nodes": [ {"id": "start", "type": "START"}, {"id": "leader_approve", "type": "APPROVAL", "assignee": "$applicant.leader"} ] } ``` 2. **流程引擎核心** - 基于状态机驱动流程流转 - 核心接口设计: ```java public interface WorkflowEngine { ProcessInstance startProcess(String processId, Map<String,Object> variables); void completeTask(String taskId, Map<String,Object> variables); } ``` ### 二、关键技术实现 1. **流程解析器** ```java public class BPMNParser { public ProcessDefinition parse(InputStream bpmnFile) { // 解析BPMN2.0或自定义格式 } } ``` 2. **任务调度机制** - 使用线程池处理异步任务 - 实现任务监听器: ```java @Component public class ApprovalTaskListener { @Async public void handleTaskComplete(TaskCompletedEvent event) { // 触发下一节点 } } ``` 3. **持久化设计** - 数据库表结构建议: ```sql CREATE TABLE wf_process_instance ( instance_id VARCHAR(36) PRIMARY KEY, process_id VARCHAR(50) NOT NULL, current_node VARCHAR(50) NOT NULL, status ENUM('RUNNING','COMPLETED') ); ``` ### 三、与企业系统集成 1. **人员组织对接** ```java public interface UserService { List<User> getApprovers(String departmentId); } ``` 2. **消息通知整合** - 支持邮件/钉钉/企业微信通知 - 配置示例: ```properties # application.properties workflow.notification.type=DINGTALK dingtalk.webhook=https://oapi.dingtalk.com/robot/send ``` ### 四、扩展开发建议 1. **会签/或签支持** ```java public class MultiInstanceNode implements WorkflowNode { public void execute(ProcessContext context) { if(approvalType == "PARALLEL") { // 并行会签逻辑 } } } ``` 2. **版本控制** - 使用数据库版本字段实现流程模板版本管理 ```sql ALTER TABLE wf_process_definition ADD version INT DEFAULT 1; ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值