viw 게시된 글

react17, typescript, ag-grid 환경에서 this.apiSet.api.forEachNode((node) => { 하여 그리드의 항목 중 activityNo:string; 항목(숫자가 입력 또는 빈값) 중 가장 큰 값을 구하고 그리드 목록 중 activityNo 빈값이 있으면 가장 큰 값에서 +1씩 증가하며 세팅하는 예제 만들어 주세요

// ActivityGrid.tsx
import React, { useRef, useCallback } from 'react';
import { AgGridReact } from 'ag-grid-react';
import { AgGridReact as AgGridReactType } from 'ag-grid-react/lib/agGridReact';
import { ColDef } from 'ag-grid-community';

import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';

interface RowDataType {
id: number;
activityNo: string;
name: string;
}

const initialRowData: RowDataType[] = [
{ id: 1, activityNo: '3', name: 'Task A' },
{ id: 2, activityNo: '', name: 'Task B' },
{ id: 3, activityNo: '10', name: 'Task C' },
{ id: 4, activityNo: '', name: 'Task D' },
{ id: 5, activityNo: '2', name: 'Task E' },
];

const columnDefs: ColDef[] = [
{ field: 'id' },
{ field: 'activityNo' },
{ field: 'name' },
];

const ActivityGrid = () => {
const gridRef = useRef<AgGridReactType>(null);

const fillActivityNumbers = useCallback(() => {

const api = gridRef.current?.api;
if (!api) return;

const nodes: RowDataType[] = [];
api.forEachNode(node => {
  if (node.data) {
    nodes.push(node.data);
  }
});

// 1. 최대 숫자 추출
const activityNumbers = nodes
  .map(row => parseInt(row.activityNo))
  .filter(num => !isNaN(num));

let max = activityNumbers.length > 0 ? Math.max(...activityNumbers) : 0;

// 2. 빈 값 채우기
nodes.forEach(row => {
  if (!row.activityNo || row.activityNo.trim() === '') {
    max += 1;
    row.activityNo = String(max);
  }
});

// 3. 변경 사항 적용
api.setRowData([...nodes]);

}, []);

return (

<div>
  <button onClick={fillActivityNumbers}>Fill Empty Activity Numbers</button>
  <div className="ag-theme-alpine" style={{ height: 300, width: 600 }}>
    <AgGridReact
      ref={gridRef}
      rowData={initialRowData}
      columnDefs={columnDefs}
      domLayout="autoHeight"
    />
  </div>
</div>

);
};

export default ActivityGrid;

mariadb에서 from_dt는 DATE 형입니다. React 화면에서 '2025-06-02T01:59:30.885Z' 전달되어 실행 결과 Incorrect data value 오류가 발생하였습니다. 해결 방법 알려주세요

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeParseException;
import java.time.format.DateTimeFormatter;

public class DateParser {

private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

/**
 * ISO 8601 문자열을 "yyyy-MM-dd" 형식 문자열로 변환
 * - 유효하지 않은 경우 null 반환
 */
public static String parseToDateString(String isoString) {
    if (isoString == null || isoString.trim().isEmpty()) {
        return null;
    }

    try {
        Instant instant = Instant.parse(isoString);
        LocalDate localDate = instant.atZone(ZoneId.systemDefault()).toLocalDate();
        return localDate.format(DATE_FORMATTER);
    } catch (DateTimeParseException e) {
        return null;
    }
}

}

아오이 츠카사, Tsukasa Aoi, 葵つかさ

아오이 츠카사 닮은 아름다운 동아시아 여성, 고운 피부와 큰 아몬드 모양의 눈, 부드러운 분홍색 입술, 섬세하고 우아한 얼굴, 온화한 눈,
부드러운 자연 채광과 함께 영화적이고 고요하며 시적인 분위기입니다.

A beautiful East Asian woman looking back over her shoulder in a snowy outdoor setting. She has a delicate and elegant face with fair skin, large almond-shaped eyes, soft pink lips, and a slightly melancholic expression. Her medium-length dark brown hair is softly swept across her face by the wind. She is wearing a dark winter coat. Gentle snowfall surrounds her, and the background is a blurred forest with muted winter colors. The atmosphere is cinematic, serene, and poetic, with soft natural lighting."

  1. 미카미 유아 (三上悠亜) 2015~ 전 SKE48 아이돌 출신, 섹시+아이돌 느낌

미카미 유아 (三上悠亜) AI가 사진 생성 할 떄 최대한 비슷하게 알 수 있도록 프롬프트 만들어 주세요

미카미 유아, Yua Mikami, 三上悠亜 닮은 여성, 명품 패션 , 자연 스럽게 팔은 아래로 , 고습스러운 블랙, 카페 앞에서 멋진 포즈를 취하고 서있는 , 카메라를 보고 있다

미카미 유아 닮은, 작은 얼굴,
부드럽고 젊은 이목구비, 큰 표정의 갈색 눈, 부드러운 분홍색 입술, 앞머리가 있는 길고 약간 물결치는 밤색 머리를 가진 아름다운 일본 젊은 여성입니다. 그녀는 매끄러운 하얀 피부, 젊고 우아한 아우라, 부드러운 미소를 짓고 있습니다. 그녀는 부드러운 광채와 함께 가벼운 자연스러운 메이크업을 하고 있습니다.
명품 Fashion , 자연 스럽게 팔은 아래로 , 고습스러운 블랙 시스룩, 카페 앞에서 멋진 포즈를 취하고 서있는 , 카메라를 보고 있다

명품 Fashion , 자연 스럽게 팔은 아래로 , 고습스러운 블랙 시스룩, 3차원 원과 삼각형을 단순화 한 흰색 배경에 아이돌의 멋진 포즈를 취하고 서있는 , 카메라를 보고 있다

"심장 모양의 얼굴,

A beautiful young Japanese woman with soft facial features, large round brown eyes, fair skin, long straight dark brown hair with front bangs. She is smiling sweetly, wearing natural makeup. Inspired by early 2010s Japanese idol aesthetics, gravure magazine photoshoots, and J-pop fashion culture.

미카미 유아, Yua Mikami, 三上悠亜

다른이름 : #본명: 키토 모모나(鬼頭桃菜/귀두도채)#예명: 미카미 유아(三上悠亜/삼상유아)#애칭: 유아짱(ゆあちゃん)#중국어표기: 싼상유야(三上悠亞)
생년월일 : 1993-08-16 (31세)
신장 : 159 cm
신체사이즈 : B83 / W57 / H88
컵사이즈 : G 컵
데뷔 : 15년 06월 데뷔

아오이 소라 닮은, 부드럽고 젊은 이목구비, 하얀 피부, 긴 생머리, 따뜻한 갈색 눈을 가진 아름다운 동아시아 여성,
명품 Fashion , 자연 스럽게 팔은 아래로 , 고습스러운 블랙 시스룩, 3차원 원과 삼각형을 단순화 한 흰색 배경에 아이돌의 멋진 포즈를 취하고 서있는 , 카메라를 보고 있다

java, spring, ibatis, mariadb 환경에서 activity 테이블에 pk는 activity_id BIGINT AUTO_INCREMENT 컬럼 입니다.
activity 테이블에 Insert하고 pk인 activity_id 리턴 받아 activity_detail 테이블에 정보를 저장하려고
합니다.
해당 예제 만들어 주세요.

Java + Spring + iBatis + MariaDB 환경에서 다음 요구사항을 만족하는 예제를 만들어드리겠습니다:

activity 테이블에 데이터를 INSERT하고, 자동 생성된 activity_id(PK)를 반환받아
✅ 그 값을 이용해 activity_detail 테이블에 데이터를 저장

✅ 1. 테이블 구조 예시

-- activity 테이블
CREATE TABLE activity (
    activity_id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- activity_detail 테이블
CREATE TABLE activity_detail (
    detail_id BIGINT AUTO_INCREMENT PRIMARY KEY,
    activity_id BIGINT,
    description TEXT,
    FOREIGN KEY (activity_id) REFERENCES activity(activity_id)
);

✅ 2. iBatis SQL Mapper 구성 (ActivityMapper.xml)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="ActivityMapper">

  <!-- 1. activity insert -->
  <insert id="insertActivity" parameterType="Activity" useGeneratedKeys="true" keyProperty="activityId">
    INSERT INTO activity (name)
    VALUES (#{name})
  </insert>

  <!-- 2. activity_detail insert -->
  <insert id="insertActivityDetail" parameterType="ActivityDetail">
    INSERT INTO activity_detail (activity_id, description)
    VALUES (#{activityId}, #{description})
  </insert>

</mapper>
useGeneratedKeys="true"keyProperty="activityId"를 사용하여 Activity 객체의 activityId 필드에 자동 증가 키를 저장합니다.

✅ 3. Java DTO 클래스

// Activity.java
public class Activity {
    private Long activityId;
    private String name;

    // getter/setter
    public Long getActivityId() { return activityId; }
    public void setActivityId(Long activityId) { this.activityId = activityId; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

// ActivityDetail.java
public class ActivityDetail {
    private Long detailId;
    private Long activityId;
    private String description;

    // getter/setter
    public Long getDetailId() { return detailId; }
    public void setDetailId(Long detailId) { this.detailId = detailId; }
    public Long getActivityId() { return activityId; }
    public void setActivityId(Long activityId) { this.activityId = activityId; }
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
}

✅ 4. DAO Interface

public interface ActivityMapper {
    void insertActivity(Activity activity);
    void insertActivityDetail(ActivityDetail activityDetail);
}

✅ 5. Service 클래스

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;

@Service
public class ActivityService {

    @Resource
    private ActivityMapper activityMapper;

    @Transactional
    public void createActivityWithDetail(String activityName, String description) {
        // 1. Activity 생성
        Activity activity = new Activity();
        activity.setName(activityName);
        activityMapper.insertActivity(activity);

        // 2. 생성된 PK(activityId)를 활용한 Detail 저장
        ActivityDetail detail = new ActivityDetail();
        detail.setActivityId(activity.getActivityId());
        detail.setDescription(description);
        activityMapper.insertActivityDetail(detail);
    }
}

✅ 6. Controller 예시

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/activity")
public class ActivityController {

    private final ActivityService activityService;

    public ActivityController(ActivityService activityService) {
        this.activityService = activityService;
    }

    @PostMapping
    public String create(@RequestParam String name, @RequestParam String description) {
        activityService.createActivityWithDetail(name, description);
        return "저장 완료";
    }
}

✅ 정리

  • @Transactional 로 두 insert를 하나의 트랜잭션으로 묶어 처리합니다.
  • useGeneratedKeys를 통해 activity_id 자동 반환받음
  • 반환된 PK를 기반으로 activity_detail에 저장

필요하시면 MyBatis Config, Spring Boot 설정 등도 도와드릴 수 있습니다.